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