3371 lines · 72.3 KB · C
RawDownload
#include <errno.h>#include <inttypes.h>#include "util.h"#include "string2.h"#include <sys/param.h>#include <sys/types.h>#include <byteswap.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <linux/compiler.h>#include <linux/list.h>#include <linux/kernel.h>#include <linux/bitops.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/utsname.h>#include <unistd.h> #include "evlist.h"#include "evsel.h"#include "header.h"#include "memswap.h"#include "../perf.h"#include "trace-event.h"#include "session.h"#include "symbol.h"#include "debug.h"#include "cpumap.h"#include "pmu.h"#include "vdso.h"#include "strbuf.h"#include "build-id.h"#include "data.h"#include <api/fs/fs.h>#include "asm/bug.h" #include "sane_ctype.h" /* * magic2 = "PERFILE2" * must be a numerical value to let the endianness * determine the memory layout. That way we are able * to detect endianness when reading the perf.data file * back. * * we check for legacy (PERFFILE) format. */static const char *__perf_magic1 = "PERFFILE";static const u64 __perf_magic2    = 0x32454c4946524550ULL;static const u64 __perf_magic2_sw = 0x50455246494c4532ULL; #define PERF_MAGIC	__perf_magic2 const char perf_version_string[] = PERF_VERSION; struct perf_file_attr {	struct perf_event_attr	attr;	struct perf_file_section	ids;}; void perf_header__set_feat(struct perf_header *header, int feat){	set_bit(feat, header->adds_features);} void perf_header__clear_feat(struct perf_header *header, int feat){	clear_bit(feat, header->adds_features);} bool perf_header__has_feat(const struct perf_header *header, int feat){	return test_bit(feat, header->adds_features);} static int do_write(int fd, const void *buf, size_t size){	while (size) {		int ret = write(fd, buf, size); 		if (ret < 0)			return -errno; 		size -= ret;		buf += ret;	} 	return 0;} int write_padded(int fd, const void *bf, size_t count, size_t count_aligned){	static const char zero_buf[NAME_ALIGN];	int err = do_write(fd, bf, count); 	if (!err)		err = do_write(fd, zero_buf, count_aligned - count); 	return err;} #define string_size(str)						\	(PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32)) static int do_write_string(int fd, const char *str){	u32 len, olen;	int ret; 	olen = strlen(str) + 1;	len = PERF_ALIGN(olen, NAME_ALIGN); 	/* write len, incl. \0 */	ret = do_write(fd, &len, sizeof(len));	if (ret < 0)		return ret; 	return write_padded(fd, str, olen, len);} static char *do_read_string(int fd, struct perf_header *ph){	ssize_t sz, ret;	u32 len;	char *buf; 	sz = readn(fd, &len, sizeof(len));	if (sz < (ssize_t)sizeof(len))		return NULL; 	if (ph->needs_swap)		len = bswap_32(len); 	buf = malloc(len);	if (!buf)		return NULL; 	ret = readn(fd, buf, len);	if (ret == (ssize_t)len) {		/*		 * strings are padded by zeroes		 * thus the actual strlen of buf		 * may be less than len		 */		return buf;	} 	free(buf);	return NULL;} static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,			    struct perf_evlist *evlist){	return read_tracing_data(fd, &evlist->entries);}  static int write_build_id(int fd, struct perf_header *h,			  struct perf_evlist *evlist __maybe_unused){	struct perf_session *session;	int err; 	session = container_of(h, struct perf_session, header); 	if (!perf_session__read_build_ids(session, true))		return -1; 	err = perf_session__write_buildid_table(session, fd);	if (err < 0) {		pr_debug("failed to write buildid table\n");		return err;	}	perf_session__cache_build_ids(session); 	return 0;} static int write_hostname(int fd, struct perf_header *h __maybe_unused,			  struct perf_evlist *evlist __maybe_unused){	struct utsname uts;	int ret; 	ret = uname(&uts);	if (ret < 0)		return -1; 	return do_write_string(fd, uts.nodename);} static int write_osrelease(int fd, struct perf_header *h __maybe_unused,			   struct perf_evlist *evlist __maybe_unused){	struct utsname uts;	int ret; 	ret = uname(&uts);	if (ret < 0)		return -1; 	return do_write_string(fd, uts.release);} static int write_arch(int fd, struct perf_header *h __maybe_unused,		      struct perf_evlist *evlist __maybe_unused){	struct utsname uts;	int ret; 	ret = uname(&uts);	if (ret < 0)		return -1; 	return do_write_string(fd, uts.machine);} static int write_version(int fd, struct perf_header *h __maybe_unused,			 struct perf_evlist *evlist __maybe_unused){	return do_write_string(fd, perf_version_string);} static int __write_cpudesc(int fd, const char *cpuinfo_proc){	FILE *file;	char *buf = NULL;	char *s, *p;	const char *search = cpuinfo_proc;	size_t len = 0;	int ret = -1; 	if (!search)		return -1; 	file = fopen("/proc/cpuinfo", "r");	if (!file)		return -1; 	while (getline(&buf, &len, file) > 0) {		ret = strncmp(buf, search, strlen(search));		if (!ret)			break;	} 	if (ret) {		ret = -1;		goto done;	} 	s = buf; 	p = strchr(buf, ':');	if (p && *(p+1) == ' ' && *(p+2))		s = p + 2;	p = strchr(s, '\n');	if (p)		*p = '\0'; 	/* squash extra space characters (branding string) */	p = s;	while (*p) {		if (isspace(*p)) {			char *r = p + 1;			char *q = r;			*p = ' ';			while (*q && isspace(*q))				q++;			if (q != (p+1))				while ((*r++ = *q++));		}		p++;	}	ret = do_write_string(fd, s);done:	free(buf);	fclose(file);	return ret;} static int write_cpudesc(int fd, struct perf_header *h __maybe_unused,		       struct perf_evlist *evlist __maybe_unused){#ifndef CPUINFO_PROC#define CPUINFO_PROC {"model name", }#endif	const char *cpuinfo_procs[] = CPUINFO_PROC;	unsigned int i; 	for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) {		int ret;		ret = __write_cpudesc(fd, cpuinfo_procs[i]);		if (ret >= 0)			return ret;	}	return -1;}  static int write_nrcpus(int fd, struct perf_header *h __maybe_unused,			struct perf_evlist *evlist __maybe_unused){	long nr;	u32 nrc, nra;	int ret; 	nrc = cpu__max_present_cpu(); 	nr = sysconf(_SC_NPROCESSORS_ONLN);	if (nr < 0)		return -1; 	nra = (u32)(nr & UINT_MAX); 	ret = do_write(fd, &nrc, sizeof(nrc));	if (ret < 0)		return ret; 	return do_write(fd, &nra, sizeof(nra));} static int write_event_desc(int fd, struct perf_header *h __maybe_unused,			    struct perf_evlist *evlist){	struct perf_evsel *evsel;	u32 nre, nri, sz;	int ret; 	nre = evlist->nr_entries; 	/*	 * write number of events	 */	ret = do_write(fd, &nre, sizeof(nre));	if (ret < 0)		return ret; 	/*	 * size of perf_event_attr struct	 */	sz = (u32)sizeof(evsel->attr);	ret = do_write(fd, &sz, sizeof(sz));	if (ret < 0)		return ret; 	evlist__for_each_entry(evlist, evsel) {		ret = do_write(fd, &evsel->attr, sz);		if (ret < 0)			return ret;		/*		 * write number of unique id per event		 * there is one id per instance of an event		 *		 * copy into an nri to be independent of the		 * type of ids,		 */		nri = evsel->ids;		ret = do_write(fd, &nri, sizeof(nri));		if (ret < 0)			return ret; 		/*		 * write event string as passed on cmdline		 */		ret = do_write_string(fd, perf_evsel__name(evsel));		if (ret < 0)			return ret;		/*		 * write unique ids for this event		 */		ret = do_write(fd, evsel->id, evsel->ids * sizeof(u64));		if (ret < 0)			return ret;	}	return 0;} static int write_cmdline(int fd, struct perf_header *h __maybe_unused,			 struct perf_evlist *evlist __maybe_unused){	char buf[MAXPATHLEN];	u32 n;	int i, ret; 	/* actual path to perf binary */	ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1);	if (ret <= 0)		return -1; 	/* readlink() does not add null termination */	buf[ret] = '\0'; 	/* account for binary path */	n = perf_env.nr_cmdline + 1; 	ret = do_write(fd, &n, sizeof(n));	if (ret < 0)		return ret; 	ret = do_write_string(fd, buf);	if (ret < 0)		return ret; 	for (i = 0 ; i < perf_env.nr_cmdline; i++) {		ret = do_write_string(fd, perf_env.cmdline_argv[i]);		if (ret < 0)			return ret;	}	return 0;} #define CORE_SIB_FMT \	"/sys/devices/system/cpu/cpu%d/topology/core_siblings_list"#define THRD_SIB_FMT \	"/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list" struct cpu_topo {	u32 cpu_nr;	u32 core_sib;	u32 thread_sib;	char **core_siblings;	char **thread_siblings;}; static int build_cpu_topo(struct cpu_topo *tp, int cpu){	FILE *fp;	char filename[MAXPATHLEN];	char *buf = NULL, *p;	size_t len = 0;	ssize_t sret;	u32 i = 0;	int ret = -1; 	sprintf(filename, CORE_SIB_FMT, cpu);	fp = fopen(filename, "r");	if (!fp)		goto try_threads; 	sret = getline(&buf, &len, fp);	fclose(fp);	if (sret <= 0)		goto try_threads; 	p = strchr(buf, '\n');	if (p)		*p = '\0'; 	for (i = 0; i < tp->core_sib; i++) {		if (!strcmp(buf, tp->core_siblings[i]))			break;	}	if (i == tp->core_sib) {		tp->core_siblings[i] = buf;		tp->core_sib++;		buf = NULL;		len = 0;	}	ret = 0; try_threads:	sprintf(filename, THRD_SIB_FMT, cpu);	fp = fopen(filename, "r");	if (!fp)		goto done; 	if (getline(&buf, &len, fp) <= 0)		goto done; 	p = strchr(buf, '\n');	if (p)		*p = '\0'; 	for (i = 0; i < tp->thread_sib; i++) {		if (!strcmp(buf, tp->thread_siblings[i]))			break;	}	if (i == tp->thread_sib) {		tp->thread_siblings[i] = buf;		tp->thread_sib++;		buf = NULL;	}	ret = 0;done:	if(fp)		fclose(fp);	free(buf);	return ret;} static void free_cpu_topo(struct cpu_topo *tp){	u32 i; 	if (!tp)		return; 	for (i = 0 ; i < tp->core_sib; i++)

Lines 1–500 of 3371.