linux/tools/perf/util/util.c

364 lines
5.9 KiB
C

#include "../perf.h"
#include "util.h"
#include <sys/mman.h>
#ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h>
#endif
#include <stdio.h>
#include <stdlib.h>
/*
* 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 HAVE_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;
}