Commit a21ca2ca authored by Ingo Molnar's avatar Ingo Molnar
Browse files

perf_counter: Separate out attr->type from attr->config



Counter type is a frequently used value and we do a lot of
bit juggling by encoding and decoding it from attr->config.

Clean this up by creating a separate attr->type field.

Also clean up the various similarly complex user-space bits
all around counter attribute management.

The net improvement is significant, and it will be easier
to add a new major type (which is what triggered this cleanup).

(This changes the ABI, all tools are adapted.)
(PowerPC build-tested.)

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 2f335a02
Loading
Loading
Loading
Loading
+47 −58
Original line number Diff line number Diff line
@@ -20,10 +20,10 @@
#define ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask)	(((x)+(mask))&~(mask))

static int			fd[MAX_NR_CPUS][MAX_COUNTERS];

static long			default_interval		= 100000;
static long			event_count[MAX_COUNTERS];

static int			fd[MAX_NR_CPUS][MAX_COUNTERS];
static int			nr_cpus				= 0;
static unsigned int		page_size;
static unsigned int		mmap_pages			= 128;
@@ -38,15 +38,35 @@ static int inherit = 1;
static int			force				= 0;
static int			append_file			= 0;

const unsigned int default_count[] = {
	1000000,
	1000000,
	  10000,
	  10000,
	1000000,
	  10000,
static long			samples;
static struct timeval		last_read;
static struct timeval		this_read;

static __u64			bytes_written;

static struct pollfd		event_array[MAX_NR_CPUS * MAX_COUNTERS];

static int			nr_poll;
static int			nr_cpu;

struct mmap_event {
	struct perf_event_header	header;
	__u32				pid;
	__u32				tid;
	__u64				start;
	__u64				len;
	__u64				pgoff;
	char				filename[PATH_MAX];
};

struct comm_event {
	struct perf_event_header	header;
	__u32				pid;
	__u32				tid;
	char				comm[16];
};


struct mmap_data {
	int			counter;
	void			*base;
@@ -54,6 +74,8 @@ struct mmap_data {
	unsigned int		prev;
};

static struct mmap_data		mmap_array[MAX_NR_CPUS][MAX_COUNTERS];

static unsigned int mmap_read_head(struct mmap_data *md)
{
	struct perf_counter_mmap_page *pc = md->base;
@@ -65,11 +87,6 @@ static unsigned int mmap_read_head(struct mmap_data *md)
	return head;
}

static long samples;
static struct timeval last_read, this_read;

static __u64 bytes_written;

static void mmap_read(struct mmap_data *md)
{
	unsigned int head = mmap_read_head(md);
@@ -157,29 +174,6 @@ static void sig_handler(int sig)
	done = 1;
}

static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];

static int nr_poll;
static int nr_cpu;

struct mmap_event {
	struct perf_event_header	header;
	__u32				pid;
	__u32				tid;
	__u64				start;
	__u64				len;
	__u64				pgoff;
	char				filename[PATH_MAX];
};

struct comm_event {
	struct perf_event_header	header;
	__u32				pid;
	__u32				tid;
	char				comm[16];
};

static void pid_synthesize_comm_event(pid_t pid, int full)
{
	struct comm_event comm_ev;
@@ -341,24 +335,21 @@ static int group_fd;

static void create_counter(int counter, int cpu, pid_t pid)
{
	struct perf_counter_attr attr;
	struct perf_counter_attr *attr = attrs + counter;
	int track = 1;

	memset(&attr, 0, sizeof(attr));
	attr.config		= event_id[counter];
	attr.sample_period	= event_count[counter];
	attr.sample_type	= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD;
	attr->sample_type	= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD;
	if (freq) {
		attr.freq		= 1;
		attr.sample_freq	= freq;
		attr->freq		= 1;
		attr->sample_freq	= freq;
	}
	attr.mmap		= track;
	attr.comm		= track;
	attr.inherit		= (cpu < 0) && inherit;
	attr->mmap		= track;
	attr->comm		= track;
	attr->inherit		= (cpu < 0) && inherit;

	track = 0; /* only the first counter needs these */

	fd[nr_cpu][counter] = sys_perf_counter_open(&attr, pid, cpu, group_fd, 0);
	fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);

	if (fd[nr_cpu][counter] < 0) {
		int err = errno;
@@ -542,16 +533,14 @@ int cmd_record(int argc, const char **argv, const char *prefix)
	if (!argc && target_pid == -1 && !system_wide)
		usage_with_options(record_usage, options);

	if (!nr_counters) {
	if (!nr_counters)
		nr_counters = 1;
		event_id[0] = 0;
	}

	for (counter = 0; counter < nr_counters; counter++) {
		if (event_count[counter])
		if (attrs[counter].sample_period)
			continue;

		event_count[counter] = default_interval;
		attrs[counter].sample_period = default_interval;
	}

	return __cmd_record(argc, argv);
+32 −44
Original line number Diff line number Diff line
@@ -44,23 +44,22 @@

#include <sys/prctl.h>

static int			system_wide			=  0;
static int			inherit				=  1;
static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {

static __u64			default_event_id[MAX_COUNTERS]	= {
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_TASK_CLOCK		},
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_CONTEXT_SWITCHES	},
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_CPU_MIGRATIONS	},
  { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_PAGE_FAULTS	},

	EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),
	EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS),
	EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),
	EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),
  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CPU_CYCLES		},
  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_INSTRUCTIONS	},
  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CACHE_REFERENCES	},
  { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CACHE_MISSES	},
};

static int			default_interval = 100000;
static int			event_count[MAX_COUNTERS];
static int			system_wide			=  0;
static int			inherit				=  1;

static int			fd[MAX_NR_CPUS][MAX_COUNTERS];

static int			target_pid			= -1;
@@ -86,22 +85,16 @@ static __u64 walltime_nsecs;

static void create_perfstat_counter(int counter)
{
	struct perf_counter_attr attr;

	memset(&attr, 0, sizeof(attr));
	attr.config		= event_id[counter];
	attr.sample_type	= 0;
	attr.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL;
	attr.exclude_user   = event_mask[counter] & EVENT_MASK_USER;
	struct perf_counter_attr *attr = attrs + counter;

	if (scale)
		attr.read_format	= PERF_FORMAT_TOTAL_TIME_ENABLED |
		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
				    PERF_FORMAT_TOTAL_TIME_RUNNING;

	if (system_wide) {
		int cpu;
		for (cpu = 0; cpu < nr_cpus; cpu ++) {
			fd[cpu][counter] = sys_perf_counter_open(&attr, -1, cpu, -1, 0);
			fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
			if (fd[cpu][counter] < 0) {
				printf("perfstat error: syscall returned with %d (%s)\n",
						fd[cpu][counter], strerror(errno));
@@ -109,10 +102,10 @@ static void create_perfstat_counter(int counter)
			}
		}
	} else {
		attr.inherit	= inherit;
		attr.disabled	= 1;
		attr->inherit	= inherit;
		attr->disabled	= 1;

		fd[0][counter] = sys_perf_counter_open(&attr, 0, -1, -1, 0);
		fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0);
		if (fd[0][counter] < 0) {
			printf("perfstat error: syscall returned with %d (%s)\n",
					fd[0][counter], strerror(errno));
@@ -126,9 +119,13 @@ static void create_perfstat_counter(int counter)
 */
static inline int nsec_counter(int counter)
{
	if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK))
	if (attrs[counter].type != PERF_TYPE_SOFTWARE)
		return 0;

	if (attrs[counter].config == PERF_COUNT_CPU_CLOCK)
		return 1;
	if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK))

	if (attrs[counter].config == PERF_COUNT_TASK_CLOCK)
		return 1;

	return 0;
@@ -177,7 +174,8 @@ static void read_counter(int counter)
	/*
	 * Save the full runtime - to allow normalization during printout:
	 */
	if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK))
	if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
		attrs[counter].config == PERF_COUNT_TASK_CLOCK)
		runtime_nsecs = count[0];
}

@@ -203,8 +201,8 @@ static void print_counter(int counter)

		fprintf(stderr, " %14.6f  %-20s",
			msecs, event_name(counter));
		if (event_id[counter] ==
				EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK)) {
		if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
			attrs[counter].config == PERF_COUNT_TASK_CLOCK) {

			fprintf(stderr, " # %11.3f CPU utilization factor",
				(double)count[0] / (double)walltime_nsecs);
@@ -300,8 +298,6 @@ static char events_help_msg[EVENTS_HELP_MAX];
static const struct option options[] = {
	OPT_CALLBACK('e', "event", NULL, "event",
		     events_help_msg, parse_events),
	OPT_INTEGER('c', "count", &default_interval,
		    "event period to sample"),
	OPT_BOOLEAN('i', "inherit", &inherit,
		    "child tasks inherit counters"),
	OPT_INTEGER('p', "pid", &target_pid,
@@ -315,27 +311,19 @@ static const struct option options[] = {

int cmd_stat(int argc, const char **argv, const char *prefix)
{
	int counter;

	page_size = sysconf(_SC_PAGE_SIZE);

	create_events_help(events_help_msg);
	memcpy(event_id, default_event_id, sizeof(default_event_id));

	memcpy(attrs, default_attrs, sizeof(attrs));

	argc = parse_options(argc, argv, options, stat_usage, 0);
	if (!argc)
		usage_with_options(stat_usage, options);

	if (!nr_counters) {
	if (!nr_counters)
		nr_counters = 8;
	}

	for (counter = 0; counter < nr_counters; counter++) {
		if (event_count[counter])
			continue;

		event_count[counter] = default_interval;
	}
	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
	assert(nr_cpus <= MAX_NR_CPUS);
	assert(nr_cpus >= 0);
+23 −44
Original line number Diff line number Diff line
@@ -48,22 +48,11 @@
#include <linux/unistd.h>
#include <linux/types.h>

static int			system_wide			=  0;
static int			fd[MAX_NR_CPUS][MAX_COUNTERS];

static __u64			default_event_id[MAX_COUNTERS]		= {
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
	EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),
static int			system_wide			=  0;

	EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),
	EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS),
	EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),
	EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),
};
static int			default_interval		= 100000;
static int			event_count[MAX_COUNTERS];
static int			fd[MAX_NR_CPUS][MAX_COUNTERS];

static __u64			count_filter			=  5;
static int			print_entries			= 15;
@@ -85,15 +74,6 @@ static int delay_secs = 2;
static int			zero;
static int			dump_symtab;

static const unsigned int default_count[] = {
	1000000,
	1000000,
	  10000,
	  10000,
	1000000,
	  10000,
};

/*
 * Symbols
 */
@@ -213,7 +193,7 @@ static void print_sym_table(void)
		100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));

	if (nr_counters == 1) {
		printf("%d", event_count[0]);
		printf("%Ld", attrs[0].sample_period);
		if (freq)
			printf("Hz ");
		else
@@ -539,7 +519,7 @@ static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];

static int __cmd_top(void)
{
	struct perf_counter_attr attr;
	struct perf_counter_attr *attr;
	pthread_t thread;
	int i, counter, group_fd, nr_poll = 0;
	unsigned int cpu;
@@ -553,13 +533,12 @@ static int __cmd_top(void)
			if (target_pid == -1 && profile_cpu == -1)
				cpu = i;

			memset(&attr, 0, sizeof(attr));
			attr.config		= event_id[counter];
			attr.sample_period	= event_count[counter];
			attr.sample_type	= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
			attr.freq		= freq;
			attr = attrs + counter;

			attr->sample_type	= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
			attr->freq		= freq;

			fd[i][counter] = sys_perf_counter_open(&attr, target_pid, cpu, group_fd, 0);
			fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
			if (fd[i][counter] < 0) {
				int err = errno;

@@ -670,7 +649,6 @@ int cmd_top(int argc, const char **argv, const char *prefix)
	page_size = sysconf(_SC_PAGE_SIZE);

	create_events_help(events_help_msg);
	memcpy(event_id, default_event_id, sizeof(default_event_id));

	argc = parse_options(argc, argv, options, top_usage, 0);
	if (argc)
@@ -688,19 +666,22 @@ int cmd_top(int argc, const char **argv, const char *prefix)
		profile_cpu = -1;
	}

	if (!nr_counters) {
	if (!nr_counters)
		nr_counters = 1;
		event_id[0] = 0;
	}

	if (delay_secs < 1)
		delay_secs = 1;

	parse_symbols();

	/*
	 * Fill in the ones not specifically initialized via -c:
	 */
	for (counter = 0; counter < nr_counters; counter++) {
		if (event_count[counter])
		if (attrs[counter].sample_period)
			continue;

		event_count[counter] = default_interval;
		attrs[counter].sample_period = default_interval;
	}

	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -710,7 +691,5 @@ int cmd_top(int argc, const char **argv, const char *prefix)
	if (target_pid != -1 || profile_cpu != -1)
		nr_cpus = 1;

	parse_symbols();

	return __cmd_top();
}
+0 −2
Original line number Diff line number Diff line
@@ -64,6 +64,4 @@ sys_perf_counter_open(struct perf_counter_attr *attr_uptr,
#define MAX_COUNTERS			256
#define MAX_NR_CPUS			256

#define EID(type, id) (((__u64)(type) << PERF_COUNTER_TYPE_SHIFT) | (id))

#endif
+66 −54
Original line number Diff line number Diff line
@@ -8,35 +8,37 @@

int					nr_counters;

__u64			event_id[MAX_COUNTERS]		= { };
int			event_mask[MAX_COUNTERS];
struct perf_counter_attr		attrs[MAX_COUNTERS];

struct event_symbol {
	__u64 event;
	__u8	type;
	__u64	config;
	char	*symbol;
};

#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y

static struct event_symbol event_symbols[] = {
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),		"cpu-cycles",		},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),		"cycles",		},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS),		"instructions",		},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),		"cache-references",	},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),		"cache-misses",		},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS),	"branch-instructions",	},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS),	"branches",		},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES),		"branch-misses",	},
	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES),		"bus-cycles",		},

	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK),			"cpu-clock",		},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),		"task-clock",		},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),		"page-faults",		},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),		"faults",		},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN),		"minor-faults",		},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ),		"major-faults",		},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),		"context-switches",	},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),		"cs",			},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),		"cpu-migrations",	},
	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),		"migrations",		},
  { C(HARDWARE, CPU_CYCLES),		"cpu-cycles",		},
  { C(HARDWARE, CPU_CYCLES),		"cycles",		},
  { C(HARDWARE, INSTRUCTIONS),		"instructions",		},
  { C(HARDWARE, CACHE_REFERENCES),	"cache-references",	},
  { C(HARDWARE, CACHE_MISSES),		"cache-misses",		},
  { C(HARDWARE, BRANCH_INSTRUCTIONS),	"branch-instructions",	},
  { C(HARDWARE, BRANCH_INSTRUCTIONS),	"branches",		},
  { C(HARDWARE, BRANCH_MISSES),		"branch-misses",	},
  { C(HARDWARE, BUS_CYCLES),		"bus-cycles",		},

  { C(SOFTWARE, CPU_CLOCK),		"cpu-clock",		},
  { C(SOFTWARE, TASK_CLOCK),		"task-clock",		},
  { C(SOFTWARE, PAGE_FAULTS),		"page-faults",		},
  { C(SOFTWARE, PAGE_FAULTS),		"faults",		},
  { C(SOFTWARE, PAGE_FAULTS_MIN),	"minor-faults",		},
  { C(SOFTWARE, PAGE_FAULTS_MAJ),	"major-faults",		},
  { C(SOFTWARE, CONTEXT_SWITCHES),	"context-switches",	},
  { C(SOFTWARE, CONTEXT_SWITCHES),	"cs",			},
  { C(SOFTWARE, CPU_MIGRATIONS),	"cpu-migrations",	},
  { C(SOFTWARE, CPU_MIGRATIONS),	"migrations",		},
};

#define __PERF_COUNTER_FIELD(config, name) \
@@ -67,27 +69,26 @@ static char *sw_event_names[] = {
	"major faults",
};

char *event_name(int ctr)
char *event_name(int counter)
{
	__u64 config = event_id[ctr];
	int type = PERF_COUNTER_TYPE(config);
	int id = PERF_COUNTER_ID(config);
	__u64 config = attrs[counter].config;
	int type = attrs[counter].type;
	static char buf[32];

	if (PERF_COUNTER_RAW(config)) {
		sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config));
	if (attrs[counter].type == PERF_TYPE_RAW) {
		sprintf(buf, "raw 0x%llx", config);
		return buf;
	}

	switch (type) {
	case PERF_TYPE_HARDWARE:
		if (id < PERF_HW_EVENTS_MAX)
			return hw_event_names[id];
		if (config < PERF_HW_EVENTS_MAX)
			return hw_event_names[config];
		return "unknown-hardware";

	case PERF_TYPE_SOFTWARE:
		if (id < PERF_SW_EVENTS_MAX)
			return sw_event_names[id];
		if (config < PERF_SW_EVENTS_MAX)
			return sw_event_names[config];
		return "unknown-software";

	default:
@@ -101,15 +102,19 @@ char *event_name(int ctr)
 * Each event can have multiple symbolic names.
 * Symbolic names are (almost) exactly matched.
 */
static __u64 match_event_symbols(const char *str)
static int match_event_symbols(const char *str, struct perf_counter_attr *attr)
{
	__u64 config, id;
	int type;
	unsigned int i;
	const char *sep, *pstr;

	if (str[0] == 'r' && hex2u64(str + 1, &config) > 0)
		return config | PERF_COUNTER_RAW_MASK;
	if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
		attr->type = PERF_TYPE_RAW;
		attr->config = config;

		return 0;
	}

	pstr = str;
	sep = strchr(pstr, ':');
@@ -121,35 +126,45 @@ static __u64 match_event_symbols(const char *str)
		if (sep) {
			pstr = sep + 1;
			if (strchr(pstr, 'k'))
				event_mask[nr_counters] |= EVENT_MASK_USER;
				attr->exclude_user = 1;
			if (strchr(pstr, 'u'))
				event_mask[nr_counters] |= EVENT_MASK_KERNEL;
				attr->exclude_kernel = 1;
		}
		return EID(type, id);
		attr->type = type;
		attr->config = id;

		return 0;
	}

	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
		if (!strncmp(str, event_symbols[i].symbol,
			     strlen(event_symbols[i].symbol)))
			return event_symbols[i].event;
			     strlen(event_symbols[i].symbol))) {

			attr->type = event_symbols[i].type;
			attr->config = event_symbols[i].config;

			return 0;
		}
	}

	return ~0ULL;
	return -EINVAL;
}

int parse_events(const struct option *opt, const char *str, int unset)
{
	__u64 config;
	struct perf_counter_attr attr;
	int ret;

	memset(&attr, 0, sizeof(attr));
again:
	if (nr_counters == MAX_COUNTERS)
		return -1;

	config = match_event_symbols(str);
	if (config == ~0ULL)
		return -1;
	ret = match_event_symbols(str, &attr);
	if (ret < 0)
		return ret;

	event_id[nr_counters] = config;
	attrs[nr_counters] = attr;
	nr_counters++;

	str = strstr(str, ",");
@@ -168,7 +183,6 @@ void create_events_help(char *events_help_msg)
{
	unsigned int i;
	char *str;
	__u64 e;

	str = events_help_msg;

@@ -178,9 +192,8 @@ void create_events_help(char *events_help_msg)
	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
		int type, id;

		e = event_symbols[i].event;
		type = PERF_COUNTER_TYPE(e);
		id = PERF_COUNTER_ID(e);
		type = event_symbols[i].type;
		id = event_symbols[i].config;

		if (i)
			str += sprintf(str, "|");
@@ -191,4 +204,3 @@ void create_events_help(char *events_help_msg)

	str += sprintf(str, "|rNNN]");
}
Loading