]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/util/util.c
3ee410fc047a7ac00e0fe523eca921776e51e207
[linux.git] / tools / perf / util / util.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "../perf.h"
3 #include "util.h"
4 #include "debug.h"
5 #include "namespaces.h"
6 #include <api/fs/fs.h>
7 #include <sys/mman.h>
8 #include <sys/stat.h>
9 #include <sys/utsname.h>
10 #include <dirent.h>
11 #include <fcntl.h>
12 #include <inttypes.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <limits.h>
19 #include <linux/kernel.h>
20 #include <linux/log2.h>
21 #include <linux/time64.h>
22 #include <unistd.h>
23 #include "strlist.h"
24
25 /*
26  * XXX We need to find a better place for these things...
27  */
28
29 bool perf_singlethreaded = true;
30
31 void perf_set_singlethreaded(void)
32 {
33         perf_singlethreaded = true;
34 }
35
36 void perf_set_multithreaded(void)
37 {
38         perf_singlethreaded = false;
39 }
40
41 unsigned int page_size;
42
43 #ifdef _SC_LEVEL1_DCACHE_LINESIZE
44 #define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE)
45 #else
46 static void cache_line_size(int *cacheline_sizep)
47 {
48         if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep))
49                 pr_debug("cannot determine cache line size");
50 }
51 #endif
52
53 int cacheline_size(void)
54 {
55         static int size;
56
57         if (!size)
58                 cache_line_size(&size);
59
60         return size;
61 }
62
63 int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
64 int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
65
66 int sysctl__max_stack(void)
67 {
68         int value;
69
70         if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
71                 sysctl_perf_event_max_stack = value;
72
73         if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
74                 sysctl_perf_event_max_contexts_per_stack = value;
75
76         return sysctl_perf_event_max_stack;
77 }
78
79 bool test_attr__enabled;
80
81 bool perf_host  = true;
82 bool perf_guest = false;
83
84 void event_attr_init(struct perf_event_attr *attr)
85 {
86         if (!perf_host)
87                 attr->exclude_host  = 1;
88         if (!perf_guest)
89                 attr->exclude_guest = 1;
90         /* to capture ABI version */
91         attr->size = sizeof(*attr);
92 }
93
94 int mkdir_p(char *path, mode_t mode)
95 {
96         struct stat st;
97         int err;
98         char *d = path;
99
100         if (*d != '/')
101                 return -1;
102
103         if (stat(path, &st) == 0)
104                 return 0;
105
106         while (*++d == '/');
107
108         while ((d = strchr(d, '/'))) {
109                 *d = '\0';
110                 err = stat(path, &st) && mkdir(path, mode);
111                 *d++ = '/';
112                 if (err)
113                         return -1;
114                 while (*d == '/')
115                         ++d;
116         }
117         return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
118 }
119
120 int rm_rf(const char *path)
121 {
122         DIR *dir;
123         int ret;
124         struct dirent *d;
125         char namebuf[PATH_MAX];
126         struct stat statbuf;
127
128         /* Do not fail if there's no file. */
129         ret = lstat(path, &statbuf);
130         if (ret)
131                 return 0;
132
133         /* Try to remove any file we get. */
134         if (!(statbuf.st_mode & S_IFDIR))
135                 return unlink(path);
136
137         /* We have directory in path. */
138         dir = opendir(path);
139         if (dir == NULL)
140                 return -1;
141
142         while ((d = readdir(dir)) != NULL && !ret) {
143
144                 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
145                         continue;
146
147                 scnprintf(namebuf, sizeof(namebuf), "%s/%s",
148                           path, d->d_name);
149
150                 /* We have to check symbolic link itself */
151                 ret = lstat(namebuf, &statbuf);
152                 if (ret < 0) {
153                         pr_debug("stat failed: %s\n", namebuf);
154                         break;
155                 }
156
157                 if (S_ISDIR(statbuf.st_mode))
158                         ret = rm_rf(namebuf);
159                 else
160                         ret = unlink(namebuf);
161         }
162         closedir(dir);
163
164         if (ret < 0)
165                 return ret;
166
167         return rmdir(path);
168 }
169
170 /* A filter which removes dot files */
171 bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
172 {
173         return d->d_name[0] != '.';
174 }
175
176 /* lsdir reads a directory and store it in strlist */
177 struct strlist *lsdir(const char *name,
178                       bool (*filter)(const char *, struct dirent *))
179 {
180         struct strlist *list = NULL;
181         DIR *dir;
182         struct dirent *d;
183
184         dir = opendir(name);
185         if (!dir)
186                 return NULL;
187
188         list = strlist__new(NULL, NULL);
189         if (!list) {
190                 errno = ENOMEM;
191                 goto out;
192         }
193
194         while ((d = readdir(dir)) != NULL) {
195                 if (!filter || filter(name, d))
196                         strlist__add(list, d->d_name);
197         }
198
199 out:
200         closedir(dir);
201         return list;
202 }
203
204 static int slow_copyfile(const char *from, const char *to, struct nsinfo *nsi)
205 {
206         int err = -1;
207         char *line = NULL;
208         size_t n;
209         FILE *from_fp, *to_fp;
210         struct nscookie nsc;
211
212         nsinfo__mountns_enter(nsi, &nsc);
213         from_fp = fopen(from, "r");
214         nsinfo__mountns_exit(&nsc);
215         if (from_fp == NULL)
216                 goto out;
217
218         to_fp = fopen(to, "w");
219         if (to_fp == NULL)
220                 goto out_fclose_from;
221
222         while (getline(&line, &n, from_fp) > 0)
223                 if (fputs(line, to_fp) == EOF)
224                         goto out_fclose_to;
225         err = 0;
226 out_fclose_to:
227         fclose(to_fp);
228         free(line);
229 out_fclose_from:
230         fclose(from_fp);
231 out:
232         return err;
233 }
234
235 int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
236 {
237         void *ptr;
238         loff_t pgoff;
239
240         pgoff = off_in & ~(page_size - 1);
241         off_in -= pgoff;
242
243         ptr = mmap(NULL, off_in + size, PROT_READ, MAP_PRIVATE, ifd, pgoff);
244         if (ptr == MAP_FAILED)
245                 return -1;
246
247         while (size) {
248                 ssize_t ret = pwrite(ofd, ptr + off_in, size, off_out);
249                 if (ret < 0 && errno == EINTR)
250                         continue;
251                 if (ret <= 0)
252                         break;
253
254                 size -= ret;
255                 off_in += ret;
256                 off_out += ret;
257         }
258         munmap(ptr, off_in + size);
259
260         return size ? -1 : 0;
261 }
262
263 static int copyfile_mode_ns(const char *from, const char *to, mode_t mode,
264                             struct nsinfo *nsi)
265 {
266         int fromfd, tofd;
267         struct stat st;
268         int err;
269         char *tmp = NULL, *ptr = NULL;
270         struct nscookie nsc;
271
272         nsinfo__mountns_enter(nsi, &nsc);
273         err = stat(from, &st);
274         nsinfo__mountns_exit(&nsc);
275         if (err)
276                 goto out;
277         err = -1;
278
279         /* extra 'x' at the end is to reserve space for '.' */
280         if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) {
281                 tmp = NULL;
282                 goto out;
283         }
284         ptr = strrchr(tmp, '/');
285         if (!ptr)
286                 goto out;
287         ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1);
288         *ptr = '.';
289
290         tofd = mkstemp(tmp);
291         if (tofd < 0)
292                 goto out;
293
294         if (fchmod(tofd, mode))
295                 goto out_close_to;
296
297         if (st.st_size == 0) { /* /proc? do it slowly... */
298                 err = slow_copyfile(from, tmp, nsi);
299                 goto out_close_to;
300         }
301
302         nsinfo__mountns_enter(nsi, &nsc);
303         fromfd = open(from, O_RDONLY);
304         nsinfo__mountns_exit(&nsc);
305         if (fromfd < 0)
306                 goto out_close_to;
307
308         err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size);
309
310         close(fromfd);
311 out_close_to:
312         close(tofd);
313         if (!err)
314                 err = link(tmp, to);
315         unlink(tmp);
316 out:
317         free(tmp);
318         return err;
319 }
320
321 int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi)
322 {
323         return copyfile_mode_ns(from, to, 0755, nsi);
324 }
325
326 int copyfile_mode(const char *from, const char *to, mode_t mode)
327 {
328         return copyfile_mode_ns(from, to, mode, NULL);
329 }
330
331 int copyfile(const char *from, const char *to)
332 {
333         return copyfile_mode(from, to, 0755);
334 }
335
336 static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
337 {
338         void *buf_start = buf;
339         size_t left = n;
340
341         while (left) {
342                 /* buf must be treated as const if !is_read. */
343                 ssize_t ret = is_read ? read(fd, buf, left) :
344                                         write(fd, buf, left);
345
346                 if (ret < 0 && errno == EINTR)
347                         continue;
348                 if (ret <= 0)
349                         return ret;
350
351                 left -= ret;
352                 buf  += ret;
353         }
354
355         BUG_ON((size_t)(buf - buf_start) != n);
356         return n;
357 }
358
359 /*
360  * Read exactly 'n' bytes or return an error.
361  */
362 ssize_t readn(int fd, void *buf, size_t n)
363 {
364         return ion(true, fd, buf, n);
365 }
366
367 /*
368  * Write exactly 'n' bytes or return an error.
369  */
370 ssize_t writen(int fd, const void *buf, size_t n)
371 {
372         /* ion does not modify buf. */
373         return ion(false, fd, (void *)buf, n);
374 }
375
376 size_t hex_width(u64 v)
377 {
378         size_t n = 1;
379
380         while ((v >>= 4))
381                 ++n;
382
383         return n;
384 }
385
386 /*
387  * While we find nice hex chars, build a long_val.
388  * Return number of chars processed.
389  */
390 int hex2u64(const char *ptr, u64 *long_val)
391 {
392         char *p;
393
394         *long_val = strtoull(ptr, &p, 16);
395
396         return p - ptr;
397 }
398
399 int perf_event_paranoid(void)
400 {
401         int value;
402
403         if (sysctl__read_int("kernel/perf_event_paranoid", &value))
404                 return INT_MAX;
405
406         return value;
407 }
408 static int
409 fetch_ubuntu_kernel_version(unsigned int *puint)
410 {
411         ssize_t len;
412         size_t line_len = 0;
413         char *ptr, *line = NULL;
414         int version, patchlevel, sublevel, err;
415         FILE *vsig;
416
417         if (!puint)
418                 return 0;
419
420         vsig = fopen("/proc/version_signature", "r");
421         if (!vsig) {
422                 pr_debug("Open /proc/version_signature failed: %s\n",
423                          strerror(errno));
424                 return -1;
425         }
426
427         len = getline(&line, &line_len, vsig);
428         fclose(vsig);
429         err = -1;
430         if (len <= 0) {
431                 pr_debug("Reading from /proc/version_signature failed: %s\n",
432                          strerror(errno));
433                 goto errout;
434         }
435
436         ptr = strrchr(line, ' ');
437         if (!ptr) {
438                 pr_debug("Parsing /proc/version_signature failed: %s\n", line);
439                 goto errout;
440         }
441
442         err = sscanf(ptr + 1, "%d.%d.%d",
443                      &version, &patchlevel, &sublevel);
444         if (err != 3) {
445                 pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
446                          line);
447                 goto errout;
448         }
449
450         *puint = (version << 16) + (patchlevel << 8) + sublevel;
451         err = 0;
452 errout:
453         free(line);
454         return err;
455 }
456
457 int
458 fetch_kernel_version(unsigned int *puint, char *str,
459                      size_t str_size)
460 {
461         struct utsname utsname;
462         int version, patchlevel, sublevel, err;
463         bool int_ver_ready = false;
464
465         if (access("/proc/version_signature", R_OK) == 0)
466                 if (!fetch_ubuntu_kernel_version(puint))
467                         int_ver_ready = true;
468
469         if (uname(&utsname))
470                 return -1;
471
472         if (str && str_size) {
473                 strncpy(str, utsname.release, str_size);
474                 str[str_size - 1] = '\0';
475         }
476
477         if (!puint || int_ver_ready)
478                 return 0;
479
480         err = sscanf(utsname.release, "%d.%d.%d",
481                      &version, &patchlevel, &sublevel);
482
483         if (err != 3) {
484                 pr_debug("Unable to get kernel version from uname '%s'\n",
485                          utsname.release);
486                 return -1;
487         }
488
489         *puint = (version << 16) + (patchlevel << 8) + sublevel;
490         return 0;
491 }
492
493 const char *perf_tip(const char *dirpath)
494 {
495         struct strlist *tips;
496         struct str_node *node;
497         char *tip = NULL;
498         struct strlist_config conf = {
499                 .dirname = dirpath,
500                 .file_only = true,
501         };
502
503         tips = strlist__new("tips.txt", &conf);
504         if (tips == NULL)
505                 return errno == ENOENT ? NULL :
506                         "Tip: check path of tips.txt or get more memory! ;-p";
507
508         if (strlist__nr_entries(tips) == 0)
509                 goto out;
510
511         node = strlist__entry(tips, random() % strlist__nr_entries(tips));
512         if (asprintf(&tip, "Tip: %s", node->s) < 0)
513                 tip = (char *)"Tip: get more memory! ;-)";
514
515 out:
516         strlist__delete(tips);
517
518         return tip;
519 }