linux/tools/perf/util/util.c
<<
>>
Prefs
   1#include "../perf.h"
   2#include "util.h"
   3#include "fs.h"
   4#include <sys/mman.h>
   5#ifdef HAVE_BACKTRACE_SUPPORT
   6#include <execinfo.h>
   7#endif
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <string.h>
  11#include <errno.h>
  12#include <limits.h>
  13#include <byteswap.h>
  14#include <linux/kernel.h>
  15
  16/*
  17 * XXX We need to find a better place for these things...
  18 */
  19unsigned int page_size;
  20
  21bool test_attr__enabled;
  22
  23bool perf_host  = true;
  24bool perf_guest = false;
  25
  26char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
  27
  28void event_attr_init(struct perf_event_attr *attr)
  29{
  30        if (!perf_host)
  31                attr->exclude_host  = 1;
  32        if (!perf_guest)
  33                attr->exclude_guest = 1;
  34        /* to capture ABI version */
  35        attr->size = sizeof(*attr);
  36}
  37
  38int mkdir_p(char *path, mode_t mode)
  39{
  40        struct stat st;
  41        int err;
  42        char *d = path;
  43
  44        if (*d != '/')
  45                return -1;
  46
  47        if (stat(path, &st) == 0)
  48                return 0;
  49
  50        while (*++d == '/');
  51
  52        while ((d = strchr(d, '/'))) {
  53                *d = '\0';
  54                err = stat(path, &st) && mkdir(path, mode);
  55                *d++ = '/';
  56                if (err)
  57                        return -1;
  58                while (*d == '/')
  59                        ++d;
  60        }
  61        return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
  62}
  63
  64static int slow_copyfile(const char *from, const char *to, mode_t mode)
  65{
  66        int err = -1;
  67        char *line = NULL;
  68        size_t n;
  69        FILE *from_fp = fopen(from, "r"), *to_fp;
  70        mode_t old_umask;
  71
  72        if (from_fp == NULL)
  73                goto out;
  74
  75        old_umask = umask(mode ^ 0777);
  76        to_fp = fopen(to, "w");
  77        umask(old_umask);
  78        if (to_fp == NULL)
  79                goto out_fclose_from;
  80
  81        while (getline(&line, &n, from_fp) > 0)
  82                if (fputs(line, to_fp) == EOF)
  83                        goto out_fclose_to;
  84        err = 0;
  85out_fclose_to:
  86        fclose(to_fp);
  87        free(line);
  88out_fclose_from:
  89        fclose(from_fp);
  90out:
  91        return err;
  92}
  93
  94int copyfile_mode(const char *from, const char *to, mode_t mode)
  95{
  96        int fromfd, tofd;
  97        struct stat st;
  98        void *addr;
  99        int err = -1;
 100
 101        if (stat(from, &st))
 102                goto out;
 103
 104        if (st.st_size == 0) /* /proc? do it slowly... */
 105                return slow_copyfile(from, to, mode);
 106
 107        fromfd = open(from, O_RDONLY);
 108        if (fromfd < 0)
 109                goto out;
 110
 111        tofd = creat(to, mode);
 112        if (tofd < 0)
 113                goto out_close_from;
 114
 115        addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
 116        if (addr == MAP_FAILED)
 117                goto out_close_to;
 118
 119        if (write(tofd, addr, st.st_size) == st.st_size)
 120                err = 0;
 121
 122        munmap(addr, st.st_size);
 123out_close_to:
 124        close(tofd);
 125        if (err)
 126                unlink(to);
 127out_close_from:
 128        close(fromfd);
 129out:
 130        return err;
 131}
 132
 133int copyfile(const char *from, const char *to)
 134{
 135        return copyfile_mode(from, to, 0755);
 136}
 137
 138unsigned long convert_unit(unsigned long value, char *unit)
 139{
 140        *unit = ' ';
 141
 142        if (value > 1000) {
 143                value /= 1000;
 144                *unit = 'K';
 145        }
 146
 147        if (value > 1000) {
 148                value /= 1000;
 149                *unit = 'M';
 150        }
 151
 152        if (value > 1000) {
 153                value /= 1000;
 154                *unit = 'G';
 155        }
 156
 157        return value;
 158}
 159
 160static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
 161{
 162        void *buf_start = buf;
 163        size_t left = n;
 164
 165        while (left) {
 166                ssize_t ret = is_read ? read(fd, buf, left) :
 167                                        write(fd, buf, left);
 168
 169                if (ret <= 0)
 170                        return ret;
 171
 172                left -= ret;
 173                buf  += ret;
 174        }
 175
 176        BUG_ON((size_t)(buf - buf_start) != n);
 177        return n;
 178}
 179
 180/*
 181 * Read exactly 'n' bytes or return an error.
 182 */
 183ssize_t readn(int fd, void *buf, size_t n)
 184{
 185        return ion(true, fd, buf, n);
 186}
 187
 188/*
 189 * Write exactly 'n' bytes or return an error.
 190 */
 191ssize_t writen(int fd, void *buf, size_t n)
 192{
 193        return ion(false, fd, buf, n);
 194}
 195
 196size_t hex_width(u64 v)
 197{
 198        size_t n = 1;
 199
 200        while ((v >>= 4))
 201                ++n;
 202
 203        return n;
 204}
 205
 206static int hex(char ch)
 207{
 208        if ((ch >= '0') && (ch <= '9'))
 209                return ch - '0';
 210        if ((ch >= 'a') && (ch <= 'f'))
 211                return ch - 'a' + 10;
 212        if ((ch >= 'A') && (ch <= 'F'))
 213                return ch - 'A' + 10;
 214        return -1;
 215}
 216
 217/*
 218 * While we find nice hex chars, build a long_val.
 219 * Return number of chars processed.
 220 */
 221int hex2u64(const char *ptr, u64 *long_val)
 222{
 223        const char *p = ptr;
 224        *long_val = 0;
 225
 226        while (*p) {
 227                const int hex_val = hex(*p);
 228
 229                if (hex_val < 0)
 230                        break;
 231
 232                *long_val = (*long_val << 4) | hex_val;
 233                p++;
 234        }
 235
 236        return p - ptr;
 237}
 238
 239/* Obtain a backtrace and print it to stdout. */
 240#ifdef HAVE_BACKTRACE_SUPPORT
 241void dump_stack(void)
 242{
 243        void *array[16];
 244        size_t size = backtrace(array, ARRAY_SIZE(array));
 245        char **strings = backtrace_symbols(array, size);
 246        size_t i;
 247
 248        printf("Obtained %zd stack frames.\n", size);
 249
 250        for (i = 0; i < size; i++)
 251                printf("%s\n", strings[i]);
 252
 253        free(strings);
 254}
 255#else
 256void dump_stack(void) {}
 257#endif
 258
 259void get_term_dimensions(struct winsize *ws)
 260{
 261        char *s = getenv("LINES");
 262
 263        if (s != NULL) {
 264                ws->ws_row = atoi(s);
 265                s = getenv("COLUMNS");
 266                if (s != NULL) {
 267                        ws->ws_col = atoi(s);
 268                        if (ws->ws_row && ws->ws_col)
 269                                return;
 270                }
 271        }
 272#ifdef TIOCGWINSZ
 273        if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
 274            ws->ws_row && ws->ws_col)
 275                return;
 276#endif
 277        ws->ws_row = 25;
 278        ws->ws_col = 80;
 279}
 280
 281static void set_tracing_events_path(const char *mountpoint)
 282{
 283        snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
 284                 mountpoint, "tracing/events");
 285}
 286
 287const char *perf_debugfs_mount(const char *mountpoint)
 288{
 289        const char *mnt;
 290
 291        mnt = debugfs_mount(mountpoint);
 292        if (!mnt)
 293                return NULL;
 294
 295        set_tracing_events_path(mnt);
 296
 297        return mnt;
 298}
 299
 300void perf_debugfs_set_path(const char *mntpt)
 301{
 302        snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
 303        set_tracing_events_path(mntpt);
 304}
 305
 306static const char *find_debugfs(void)
 307{
 308        const char *path = perf_debugfs_mount(NULL);
 309
 310        if (!path)
 311                fprintf(stderr, "Your kernel does not support the debugfs filesystem");
 312
 313        return path;
 314}
 315
 316/*
 317 * Finds the path to the debugfs/tracing
 318 * Allocates the string and stores it.
 319 */
 320const char *find_tracing_dir(void)
 321{
 322        static char *tracing;
 323        static int tracing_found;
 324        const char *debugfs;
 325
 326        if (tracing_found)
 327                return tracing;
 328
 329        debugfs = find_debugfs();
 330        if (!debugfs)
 331                return NULL;
 332
 333        tracing = malloc(strlen(debugfs) + 9);
 334        if (!tracing)
 335                return NULL;
 336
 337        sprintf(tracing, "%s/tracing", debugfs);
 338
 339        tracing_found = 1;
 340        return tracing;
 341}
 342
 343char *get_tracing_file(const char *name)
 344{
 345        const char *tracing;
 346        char *file;
 347
 348        tracing = find_tracing_dir();
 349        if (!tracing)
 350                return NULL;
 351
 352        file = malloc(strlen(tracing) + strlen(name) + 2);
 353        if (!file)
 354                return NULL;
 355
 356        sprintf(file, "%s/%s", tracing, name);
 357        return file;
 358}
 359
 360void put_tracing_file(char *file)
 361{
 362        free(file);
 363}
 364
 365int parse_nsec_time(const char *str, u64 *ptime)
 366{
 367        u64 time_sec, time_nsec;
 368        char *end;
 369
 370        time_sec = strtoul(str, &end, 10);
 371        if (*end != '.' && *end != '\0')
 372                return -1;
 373
 374        if (*end == '.') {
 375                int i;
 376                char nsec_buf[10];
 377
 378                if (strlen(++end) > 9)
 379                        return -1;
 380
 381                strncpy(nsec_buf, end, 9);
 382                nsec_buf[9] = '\0';
 383
 384                /* make it nsec precision */
 385                for (i = strlen(nsec_buf); i < 9; i++)
 386                        nsec_buf[i] = '0';
 387
 388                time_nsec = strtoul(nsec_buf, &end, 10);
 389                if (*end != '\0')
 390                        return -1;
 391        } else
 392                time_nsec = 0;
 393
 394        *ptime = time_sec * NSEC_PER_SEC + time_nsec;
 395        return 0;
 396}
 397
 398unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
 399{
 400        struct parse_tag *i = tags;
 401
 402        while (i->tag) {
 403                char *s;
 404
 405                s = strchr(str, i->tag);
 406                if (s) {
 407                        unsigned long int value;
 408                        char *endptr;
 409
 410                        value = strtoul(str, &endptr, 10);
 411                        if (s != endptr)
 412                                break;
 413
 414                        if (value > ULONG_MAX / i->mult)
 415                                break;
 416                        value *= i->mult;
 417                        return value;
 418                }
 419                i++;
 420        }
 421
 422        return (unsigned long) -1;
 423}
 424
 425int filename__read_int(const char *filename, int *value)
 426{
 427        char line[64];
 428        int fd = open(filename, O_RDONLY), err = -1;
 429
 430        if (fd < 0)
 431                return -1;
 432
 433        if (read(fd, line, sizeof(line)) > 0) {
 434                *value = atoi(line);
 435                err = 0;
 436        }
 437
 438        close(fd);
 439        return err;
 440}
 441
 442int filename__read_str(const char *filename, char **buf, size_t *sizep)
 443{
 444        size_t size = 0, alloc_size = 0;
 445        void *bf = NULL, *nbf;
 446        int fd, n, err = 0;
 447
 448        fd = open(filename, O_RDONLY);
 449        if (fd < 0)
 450                return -errno;
 451
 452        do {
 453                if (size == alloc_size) {
 454                        alloc_size += BUFSIZ;
 455                        nbf = realloc(bf, alloc_size);
 456                        if (!nbf) {
 457                                err = -ENOMEM;
 458                                break;
 459                        }
 460
 461                        bf = nbf;
 462                }
 463
 464                n = read(fd, bf + size, alloc_size - size);
 465                if (n < 0) {
 466                        if (size) {
 467                                pr_warning("read failed %d: %s\n",
 468                                           errno, strerror(errno));
 469                                err = 0;
 470                        } else
 471                                err = -errno;
 472
 473                        break;
 474                }
 475
 476                size += n;
 477        } while (n > 0);
 478
 479        if (!err) {
 480                *sizep = size;
 481                *buf   = bf;
 482        } else
 483                free(bf);
 484
 485        close(fd);
 486        return err;
 487}
 488
 489const char *get_filename_for_perf_kvm(void)
 490{
 491        const char *filename;
 492
 493        if (perf_host && !perf_guest)
 494                filename = strdup("perf.data.host");
 495        else if (!perf_host && perf_guest)
 496                filename = strdup("perf.data.guest");
 497        else
 498                filename = strdup("perf.data.kvm");
 499
 500        return filename;
 501}
 502
 503int perf_event_paranoid(void)
 504{
 505        char path[PATH_MAX];
 506        const char *procfs = procfs__mountpoint();
 507        int value;
 508
 509        if (!procfs)
 510                return INT_MAX;
 511
 512        scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs);
 513
 514        if (filename__read_int(path, &value))
 515                return INT_MAX;
 516
 517        return value;
 518}
 519
 520void mem_bswap_32(void *src, int byte_size)
 521{
 522        u32 *m = src;
 523        while (byte_size > 0) {
 524                *m = bswap_32(*m);
 525                byte_size -= sizeof(u32);
 526                ++m;
 527        }
 528}
 529
 530void mem_bswap_64(void *src, int byte_size)
 531{
 532        u64 *m = src;
 533
 534        while (byte_size > 0) {
 535                *m = bswap_64(*m);
 536                byte_size -= sizeof(u64);
 537                ++m;
 538        }
 539}
 540