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