#include "../perf.h" #include "util.h" #include #ifdef BACKTRACE_SUPPORT #include #endif #include #include /* * XXX We need to find a better place for these things... */ unsigned int page_size; bool test_attr__enabled; bool perf_host = true; bool perf_guest = false; char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; void event_attr_init(struct perf_event_attr *attr) { if (!perf_host) attr->exclude_host = 1; if (!perf_guest) attr->exclude_guest = 1; /* to capture ABI version */ attr->size = sizeof(*attr); } int mkdir_p(char *path, mode_t mode) { struct stat st; int err; char *d = path; if (*d != '/') return -1; if (stat(path, &st) == 0) return 0; while (*++d == '/'); while ((d = strchr(d, '/'))) { *d = '\0'; err = stat(path, &st) && mkdir(path, mode); *d++ = '/'; if (err) return -1; while (*d == '/') ++d; } return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; } static int slow_copyfile(const char *from, const char *to) { int err = 0; char *line = NULL; size_t n; FILE *from_fp = fopen(from, "r"), *to_fp; if (from_fp == NULL) goto out; to_fp = fopen(to, "w"); if (to_fp == NULL) goto out_fclose_from; while (getline(&line, &n, from_fp) > 0) if (fputs(line, to_fp) == EOF) goto out_fclose_to; err = 0; out_fclose_to: fclose(to_fp); free(line); out_fclose_from: fclose(from_fp); out: return err; } int copyfile(const char *from, const char *to) { int fromfd, tofd; struct stat st; void *addr; int err = -1; if (stat(from, &st)) goto out; if (st.st_size == 0) /* /proc? do it slowly... */ return slow_copyfile(from, to); fromfd = open(from, O_RDONLY); if (fromfd < 0) goto out; tofd = creat(to, 0755); if (tofd < 0) goto out_close_from; addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0); if (addr == MAP_FAILED) goto out_close_to; if (write(tofd, addr, st.st_size) == st.st_size) err = 0; munmap(addr, st.st_size); out_close_to: close(tofd); if (err) unlink(to); out_close_from: close(fromfd); out: return err; } unsigned long convert_unit(unsigned long value, char *unit) { *unit = ' '; if (value > 1000) { value /= 1000; *unit = 'K'; } if (value > 1000) { value /= 1000; *unit = 'M'; } if (value > 1000) { value /= 1000; *unit = 'G'; } return value; } int readn(int fd, void *buf, size_t n) { void *buf_start = buf; while (n) { int ret = read(fd, buf, n); if (ret <= 0) return ret; n -= ret; buf += ret; } return buf - buf_start; } size_t hex_width(u64 v) { size_t n = 1; while ((v >>= 4)) ++n; return n; } static int hex(char ch) { if ((ch >= '0') && (ch <= '9')) return ch - '0'; if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10; return -1; } /* * While we find nice hex chars, build a long_val. * Return number of chars processed. */ int hex2u64(const char *ptr, u64 *long_val) { const char *p = ptr; *long_val = 0; while (*p) { const int hex_val = hex(*p); if (hex_val < 0) break; *long_val = (*long_val << 4) | hex_val; p++; } return p - ptr; } /* Obtain a backtrace and print it to stdout. */ #ifdef BACKTRACE_SUPPORT void dump_stack(void) { void *array[16]; size_t size = backtrace(array, ARRAY_SIZE(array)); char **strings = backtrace_symbols(array, size); size_t i; printf("Obtained %zd stack frames.\n", size); for (i = 0; i < size; i++) printf("%s\n", strings[i]); free(strings); } #else void dump_stack(void) {} #endif void get_term_dimensions(struct winsize *ws) { char *s = getenv("LINES"); if (s != NULL) { ws->ws_row = atoi(s); s = getenv("COLUMNS"); if (s != NULL) { ws->ws_col = atoi(s); if (ws->ws_row && ws->ws_col) return; } } #ifdef TIOCGWINSZ if (ioctl(1, TIOCGWINSZ, ws) == 0 && ws->ws_row && ws->ws_col) return; #endif ws->ws_row = 25; ws->ws_col = 80; } static void set_tracing_events_path(const char *mountpoint) { snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", mountpoint, "tracing/events"); } const char *perf_debugfs_mount(const char *mountpoint) { const char *mnt; mnt = debugfs_mount(mountpoint); if (!mnt) return NULL; set_tracing_events_path(mnt); return mnt; } void perf_debugfs_set_path(const char *mntpt) { snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); set_tracing_events_path(mntpt); } static const char *find_debugfs(void) { const char *path = perf_debugfs_mount(NULL); if (!path) fprintf(stderr, "Your kernel does not support the debugfs filesystem"); return path; } /* * Finds the path to the debugfs/tracing * Allocates the string and stores it. */ const char *find_tracing_dir(void) { static char *tracing; static int tracing_found; const char *debugfs; if (tracing_found) return tracing; debugfs = find_debugfs(); if (!debugfs) return NULL; tracing = malloc(strlen(debugfs) + 9); if (!tracing) return NULL; sprintf(tracing, "%s/tracing", debugfs); tracing_found = 1; return tracing; } char *get_tracing_file(const char *name) { const char *tracing; char *file; tracing = find_tracing_dir(); if (!tracing) return NULL; file = malloc(strlen(tracing) + strlen(name) + 2); if (!file) return NULL; sprintf(file, "%s/%s", tracing, name); return file; } void put_tracing_file(char *file) { free(file); } int parse_nsec_time(const char *str, u64 *ptime) { u64 time_sec, time_nsec; char *end; time_sec = strtoul(str, &end, 10); if (*end != '.' && *end != '\0') return -1; if (*end == '.') { int i; char nsec_buf[10]; if (strlen(++end) > 9) return -1; strncpy(nsec_buf, end, 9); nsec_buf[9] = '\0'; /* make it nsec precision */ for (i = strlen(nsec_buf); i < 9; i++) nsec_buf[i] = '0'; time_nsec = strtoul(nsec_buf, &end, 10); if (*end != '\0') return -1; } else time_nsec = 0; *ptime = time_sec * NSEC_PER_SEC + time_nsec; return 0; }