parse-events.c 7.0 KB
Newer Older
1 2 3 4 5 6

#include "../perf.h"
#include "util.h"
#include "parse-options.h"
#include "parse-events.h"
#include "exec_cmd.h"
7
#include "string.h"
8

9 10
extern char *strcasestr(const char *haystack, const char *needle);

11
int					nr_counters;
12

13
struct perf_counter_attr		attrs[MAX_COUNTERS];
14 15

struct event_symbol {
16 17
	u8	type;
	u64	config;
18
	char	*symbol;
19 20
};

21 22
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
23

24
static struct event_symbol event_symbols[] = {
25 26 27 28 29 30 31 32 33
  { CHW(CPU_CYCLES),		"cpu-cycles",		},
  { CHW(CPU_CYCLES),		"cycles",		},
  { CHW(INSTRUCTIONS),		"instructions",		},
  { CHW(CACHE_REFERENCES),	"cache-references",	},
  { CHW(CACHE_MISSES),		"cache-misses",		},
  { CHW(BRANCH_INSTRUCTIONS),	"branch-instructions",	},
  { CHW(BRANCH_INSTRUCTIONS),	"branches",		},
  { CHW(BRANCH_MISSES),		"branch-misses",	},
  { CHW(BUS_CYCLES),		"bus-cycles",		},
34

35 36 37 38 39 40 41 42 43 44
  { CSW(CPU_CLOCK),		"cpu-clock",		},
  { CSW(TASK_CLOCK),		"task-clock",		},
  { CSW(PAGE_FAULTS),		"page-faults",		},
  { CSW(PAGE_FAULTS),		"faults",		},
  { CSW(PAGE_FAULTS_MIN),	"minor-faults",		},
  { CSW(PAGE_FAULTS_MAJ),	"major-faults",		},
  { CSW(CONTEXT_SWITCHES),	"context-switches",	},
  { CSW(CONTEXT_SWITCHES),	"cs",			},
  { CSW(CPU_MIGRATIONS),	"cpu-migrations",	},
  { CSW(CPU_MIGRATIONS),	"migrations",		},
45 46
};

47 48 49 50 51 52 53 54 55
#define __PERF_COUNTER_FIELD(config, name) \
	((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)

#define PERF_COUNTER_RAW(config)	__PERF_COUNTER_FIELD(config, RAW)
#define PERF_COUNTER_CONFIG(config)	__PERF_COUNTER_FIELD(config, CONFIG)
#define PERF_COUNTER_TYPE(config)	__PERF_COUNTER_FIELD(config, TYPE)
#define PERF_COUNTER_ID(config)		__PERF_COUNTER_FIELD(config, EVENT)

static char *hw_event_names[] = {
56
	"cycles",
57
	"instructions",
58 59
	"cache-references",
	"cache-misses",
60
	"branches",
61 62
	"branch-misses",
	"bus-cycles",
63 64 65
};

static char *sw_event_names[] = {
I
Ingo Molnar 已提交
66 67
	"cpu-clock-msecs",
	"task-clock-msecs",
68 69 70 71 72
	"page-faults",
	"context-switches",
	"CPU-migrations",
	"minor-faults",
	"major-faults",
73 74
};

75 76 77
#define MAX_ALIASES 8

static char *hw_cache [][MAX_ALIASES] = {
78
	{ "L1-data"		, "l1-d", "l1d"					},
79 80 81 82 83
	{ "L1-instruction"	, "l1-i", "l1i"					},
	{ "L2"			, "l2"						},
	{ "Data-TLB"		, "dtlb", "d-tlb"				},
	{ "Instruction-TLB"	, "itlb", "i-tlb"				},
	{ "Branch"		, "bpu" , "btb", "bpc"				},
84 85 86
};

static char *hw_cache_op [][MAX_ALIASES] = {
87 88 89
	{ "Load"		, "read"					},
	{ "Store"		, "write"					},
	{ "Prefetch"		, "speculative-read", "speculative-load"	},
90 91 92
};

static char *hw_cache_result [][MAX_ALIASES] = {
93 94
	{ "Reference"		, "ops", "access"				},
	{ "Miss"								},
95 96
};

97
char *event_name(int counter)
98
{
99
	u64 config = attrs[counter].config;
100
	int type = attrs[counter].type;
101 102
	static char buf[32];

103 104
	if (attrs[counter].type == PERF_TYPE_RAW) {
		sprintf(buf, "raw 0x%llx", config);
105 106 107 108 109
		return buf;
	}

	switch (type) {
	case PERF_TYPE_HARDWARE:
110
		if (config < PERF_COUNT_HW_MAX)
111
			return hw_event_names[config];
112 113
		return "unknown-hardware";

114
	case PERF_TYPE_HW_CACHE: {
115
		u8 cache_type, cache_op, cache_result;
116 117 118 119 120 121 122
		static char name[100];

		cache_type   = (config >>  0) & 0xff;
		if (cache_type > PERF_COUNT_HW_CACHE_MAX)
			return "unknown-ext-hardware-cache-type";

		cache_op     = (config >>  8) & 0xff;
123 124
		if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
			return "unknown-ext-hardware-cache-op";
125 126

		cache_result = (config >> 16) & 0xff;
127 128
		if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
			return "unknown-ext-hardware-cache-result";
129

130
		sprintf(name, "%s-Cache-%s-%ses",
131 132 133 134 135 136 137
			hw_cache[cache_type][0],
			hw_cache_op[cache_op][0],
			hw_cache_result[cache_result][0]);

		return name;
	}

138
	case PERF_TYPE_SOFTWARE:
139
		if (config < PERF_COUNT_SW_MAX)
140
			return sw_event_names[config];
141 142 143 144 145 146 147 148 149
		return "unknown-software";

	default:
		break;
	}

	return "unknown";
}

150 151 152 153 154 155 156 157 158 159 160 161 162
static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
{
	int i, j;

	for (i = 0; i < size; i++) {
		for (j = 0; j < MAX_ALIASES; j++) {
			if (!names[i][j])
				break;
			if (strcasestr(str, names[i][j]))
				return i;
		}
	}

163
	return -1;
164 165 166 167
}

static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
{
168
	int cache_type = -1, cache_op = 0, cache_result = 0;
169 170 171 172 173 174 175 176 177 178 179 180 181

	cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX);
	/*
	 * No fallback - if we cannot get a clear cache type
	 * then bail out:
	 */
	if (cache_type == -1)
		return -EINVAL;

	cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
	/*
	 * Fall back to reads:
	 */
182 183
	if (cache_op == -1)
		cache_op = PERF_COUNT_HW_CACHE_OP_READ;
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198

	cache_result = parse_aliases(str, hw_cache_result,
					PERF_COUNT_HW_CACHE_RESULT_MAX);
	/*
	 * Fall back to accesses:
	 */
	if (cache_result == -1)
		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;

	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
	attr->type = PERF_TYPE_HW_CACHE;

	return 0;
}

199 200 201 202
/*
 * Each event can have multiple symbolic names.
 * Symbolic names are (almost) exactly matched.
 */
203
static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
204
{
205
	u64 config, id;
206 207
	int type;
	unsigned int i;
208
	const char *sep, *pstr;
209

210 211 212 213 214 215
	if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
		attr->type = PERF_TYPE_RAW;
		attr->config = config;

		return 0;
	}
216

217 218 219 220 221 222 223 224 225 226
	pstr = str;
	sep = strchr(pstr, ':');
	if (sep) {
		type = atoi(pstr);
		pstr = sep + 1;
		id = atoi(pstr);
		sep = strchr(pstr, ':');
		if (sep) {
			pstr = sep + 1;
			if (strchr(pstr, 'k'))
227
				attr->exclude_user = 1;
228
			if (strchr(pstr, 'u'))
229
				attr->exclude_kernel = 1;
230
		}
231 232 233 234
		attr->type = type;
		attr->config = id;

		return 0;
235
	}
236 237 238

	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
		if (!strncmp(str, event_symbols[i].symbol,
239 240 241 242 243 244 245
			     strlen(event_symbols[i].symbol))) {

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

			return 0;
		}
246 247
	}

248
	return parse_generic_hw_symbols(str, attr);
249 250 251 252
}

int parse_events(const struct option *opt, const char *str, int unset)
{
253 254
	struct perf_counter_attr attr;
	int ret;
255

256
	memset(&attr, 0, sizeof(attr));
257 258 259 260
again:
	if (nr_counters == MAX_COUNTERS)
		return -1;

261
	ret = parse_event_symbols(str, &attr);
262 263
	if (ret < 0)
		return ret;
264

265
	attrs[nr_counters] = attr;
266 267 268 269 270 271 272 273 274 275 276
	nr_counters++;

	str = strstr(str, ",");
	if (str) {
		str++;
		goto again;
	}

	return 0;
}

277 278 279 280 281 282 283 284
static const char * const event_type_descriptors[] = {
	"",
	"Hardware event",
	"Software event",
	"Tracepoint event",
	"Hardware cache event",
};

285
/*
286
 * Print the help text for the event symbols:
287
 */
288
void print_events(void)
289
{
290 291
	struct event_symbol *syms = event_symbols;
	unsigned int i, type, prev_type = -1;
292

293 294
	fprintf(stderr, "\n");
	fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
295

296 297 298 299
	for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
		type = syms->type + 1;
		if (type > ARRAY_SIZE(event_type_descriptors))
			type = 0;
300

301 302
		if (type != prev_type)
			fprintf(stderr, "\n");
303

304 305
		fprintf(stderr, "  %-30s [%s]\n", syms->symbol,
			event_type_descriptors[type]);
306

307
		prev_type = type;
308 309
	}

310 311 312 313 314 315
	fprintf(stderr, "\n");
	fprintf(stderr, "  %-30s [raw hardware event descriptor]\n",
		"rNNN");
	fprintf(stderr, "\n");

	exit(129);
316
}