| #include "../perf.h" | 
 | #include "util.h" | 
 | #include <sys/mman.h> | 
 | #ifdef 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 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; | 
 | } |