aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-01-03 13:39:04 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-03 13:39:04 -0500
commit69aad6f1ee69546dea8535ab8f3da9f445d57328 (patch)
treeb328ec140a6a90703a049fcc661d623025d7e81f /tools/perf/builtin-top.c
parent56f4c400349157289b474a3fd49ee96acab0a4d7 (diff)
perf tools: Introduce event selectors
Out of ad-hoc code and global arrays with hard coded sizes. This is the first step on having a library that will be first used on regression tests in the 'perf test' tool. [acme@felicio linux]$ size /tmp/perf.before text data bss dec hex filename 1273776 97384 5104416 6475576 62cf38 /tmp/perf.before [acme@felicio linux]$ size /tmp/perf.new text data bss dec hex filename 1275422 97416 1392416 2765254 2a31c6 /tmp/perf.new Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c176
1 files changed, 104 insertions, 72 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ae15f046c405..13a836efa1e1 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -21,6 +21,7 @@
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/color.h" 23#include "util/color.h"
24#include "util/evsel.h"
24#include "util/session.h" 25#include "util/session.h"
25#include "util/symbol.h" 26#include "util/symbol.h"
26#include "util/thread.h" 27#include "util/thread.h"
@@ -29,6 +30,7 @@
29#include "util/parse-options.h" 30#include "util/parse-options.h"
30#include "util/parse-events.h" 31#include "util/parse-events.h"
31#include "util/cpumap.h" 32#include "util/cpumap.h"
33#include "util/xyarray.h"
32 34
33#include "util/debug.h" 35#include "util/debug.h"
34 36
@@ -55,7 +57,7 @@
55#include <linux/unistd.h> 57#include <linux/unistd.h>
56#include <linux/types.h> 58#include <linux/types.h>
57 59
58static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 60#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
59 61
60static bool system_wide = false; 62static bool system_wide = false;
61 63
@@ -100,6 +102,7 @@ struct sym_entry *sym_filter_entry = NULL;
100struct sym_entry *sym_filter_entry_sched = NULL; 102struct sym_entry *sym_filter_entry_sched = NULL;
101static int sym_pcnt_filter = 5; 103static int sym_pcnt_filter = 5;
102static int sym_counter = 0; 104static int sym_counter = 0;
105static struct perf_evsel *sym_evsel = NULL;
103static int display_weighted = -1; 106static int display_weighted = -1;
104static const char *cpu_list; 107static const char *cpu_list;
105 108
@@ -353,7 +356,7 @@ static void show_details(struct sym_entry *syme)
353 return; 356 return;
354 357
355 symbol = sym_entry__symbol(syme); 358 symbol = sym_entry__symbol(syme);
356 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 359 printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name);
357 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 360 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
358 361
359 pthread_mutex_lock(&syme->src->lock); 362 pthread_mutex_lock(&syme->src->lock);
@@ -460,7 +463,8 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
460static void print_sym_table(void) 463static void print_sym_table(void)
461{ 464{
462 int printed = 0, j; 465 int printed = 0, j;
463 int counter, snap = !display_weighted ? sym_counter : 0; 466 struct perf_evsel *counter;
467 int snap = !display_weighted ? sym_counter : 0;
464 float samples_per_sec = samples/delay_secs; 468 float samples_per_sec = samples/delay_secs;
465 float ksamples_per_sec = kernel_samples/delay_secs; 469 float ksamples_per_sec = kernel_samples/delay_secs;
466 float us_samples_per_sec = (us_samples)/delay_secs; 470 float us_samples_per_sec = (us_samples)/delay_secs;
@@ -532,7 +536,9 @@ static void print_sym_table(void)
532 } 536 }
533 537
534 if (nr_counters == 1 || !display_weighted) { 538 if (nr_counters == 1 || !display_weighted) {
535 printf("%Ld", (u64)attrs[0].sample_period); 539 struct perf_evsel *first;
540 first = list_entry(evsel_list.next, struct perf_evsel, node);
541 printf("%Ld", first->attr.sample_period);
536 if (freq) 542 if (freq)
537 printf("Hz "); 543 printf("Hz ");
538 else 544 else
@@ -540,9 +546,9 @@ static void print_sym_table(void)
540 } 546 }
541 547
542 if (!display_weighted) 548 if (!display_weighted)
543 printf("%s", event_name(sym_counter)); 549 printf("%s", event_name(sym_evsel));
544 else for (counter = 0; counter < nr_counters; counter++) { 550 else list_for_each_entry(counter, &evsel_list, node) {
545 if (counter) 551 if (counter->idx)
546 printf("/"); 552 printf("/");
547 553
548 printf("%s", event_name(counter)); 554 printf("%s", event_name(counter));
@@ -739,7 +745,7 @@ static void print_mapped_keys(void)
739 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); 745 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
740 746
741 if (nr_counters > 1) 747 if (nr_counters > 1)
742 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); 748 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel));
743 749
744 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 750 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
745 751
@@ -826,19 +832,23 @@ static void handle_keypress(struct perf_session *session, int c)
826 break; 832 break;
827 case 'E': 833 case 'E':
828 if (nr_counters > 1) { 834 if (nr_counters > 1) {
829 int i;
830
831 fprintf(stderr, "\nAvailable events:"); 835 fprintf(stderr, "\nAvailable events:");
832 for (i = 0; i < nr_counters; i++) 836
833 fprintf(stderr, "\n\t%d %s", i, event_name(i)); 837 list_for_each_entry(sym_evsel, &evsel_list, node)
838 fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel));
834 839
835 prompt_integer(&sym_counter, "Enter details event counter"); 840 prompt_integer(&sym_counter, "Enter details event counter");
836 841
837 if (sym_counter >= nr_counters) { 842 if (sym_counter >= nr_counters) {
838 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); 843 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
839 sym_counter = 0; 844 sym_counter = 0;
845 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
840 sleep(1); 846 sleep(1);
847 break;
841 } 848 }
849 list_for_each_entry(sym_evsel, &evsel_list, node)
850 if (sym_evsel->idx == sym_counter)
851 break;
842 } else sym_counter = 0; 852 } else sym_counter = 0;
843 break; 853 break;
844 case 'f': 854 case 'f':
@@ -978,7 +988,8 @@ static int symbol_filter(struct map *map, struct symbol *sym)
978 988
979static void event__process_sample(const event_t *self, 989static void event__process_sample(const event_t *self,
980 struct sample_data *sample, 990 struct sample_data *sample,
981 struct perf_session *session, int counter) 991 struct perf_session *session,
992 struct perf_evsel *evsel)
982{ 993{
983 u64 ip = self->ip.ip; 994 u64 ip = self->ip.ip;
984 struct sym_entry *syme; 995 struct sym_entry *syme;
@@ -1071,9 +1082,9 @@ static void event__process_sample(const event_t *self,
1071 1082
1072 syme = symbol__priv(al.sym); 1083 syme = symbol__priv(al.sym);
1073 if (!syme->skip) { 1084 if (!syme->skip) {
1074 syme->count[counter]++; 1085 syme->count[evsel->idx]++;
1075 syme->origin = origin; 1086 syme->origin = origin;
1076 record_precise_ip(syme, counter, ip); 1087 record_precise_ip(syme, evsel->idx, ip);
1077 pthread_mutex_lock(&active_symbols_lock); 1088 pthread_mutex_lock(&active_symbols_lock);
1078 if (list_empty(&syme->node) || !syme->node.next) 1089 if (list_empty(&syme->node) || !syme->node.next)
1079 __list_insert_active_sym(syme); 1090 __list_insert_active_sym(syme);
@@ -1082,12 +1093,24 @@ static void event__process_sample(const event_t *self,
1082} 1093}
1083 1094
1084struct mmap_data { 1095struct mmap_data {
1085 int counter;
1086 void *base; 1096 void *base;
1087 int mask; 1097 int mask;
1088 unsigned int prev; 1098 unsigned int prev;
1089}; 1099};
1090 1100
1101static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
1102 int ncpus, int nthreads)
1103{
1104 evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
1105 return evsel->priv != NULL ? 0 : -ENOMEM;
1106}
1107
1108static void perf_evsel__free_mmap(struct perf_evsel *evsel)
1109{
1110 xyarray__delete(evsel->priv);
1111 evsel->priv = NULL;
1112}
1113
1091static unsigned int mmap_read_head(struct mmap_data *md) 1114static unsigned int mmap_read_head(struct mmap_data *md)
1092{ 1115{
1093 struct perf_event_mmap_page *pc = md->base; 1116 struct perf_event_mmap_page *pc = md->base;
@@ -1100,8 +1123,11 @@ static unsigned int mmap_read_head(struct mmap_data *md)
1100} 1123}
1101 1124
1102static void perf_session__mmap_read_counter(struct perf_session *self, 1125static void perf_session__mmap_read_counter(struct perf_session *self,
1103 struct mmap_data *md) 1126 struct perf_evsel *evsel,
1127 int cpu, int thread_idx)
1104{ 1128{
1129 struct xyarray *mmap_array = evsel->priv;
1130 struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
1105 unsigned int head = mmap_read_head(md); 1131 unsigned int head = mmap_read_head(md);
1106 unsigned int old = md->prev; 1132 unsigned int old = md->prev;
1107 unsigned char *data = md->base + page_size; 1133 unsigned char *data = md->base + page_size;
@@ -1155,7 +1181,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1155 1181
1156 event__parse_sample(event, self, &sample); 1182 event__parse_sample(event, self, &sample);
1157 if (event->header.type == PERF_RECORD_SAMPLE) 1183 if (event->header.type == PERF_RECORD_SAMPLE)
1158 event__process_sample(event, &sample, self, md->counter); 1184 event__process_sample(event, &sample, self, evsel);
1159 else 1185 else
1160 event__process(event, &sample, self); 1186 event__process(event, &sample, self);
1161 old += size; 1187 old += size;
@@ -1165,28 +1191,31 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1165} 1191}
1166 1192
1167static struct pollfd *event_array; 1193static struct pollfd *event_array;
1168static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1169 1194
1170static void perf_session__mmap_read(struct perf_session *self) 1195static void perf_session__mmap_read(struct perf_session *self)
1171{ 1196{
1172 int i, counter, thread_index; 1197 struct perf_evsel *counter;
1198 int i, thread_index;
1173 1199
1174 for (i = 0; i < nr_cpus; i++) { 1200 for (i = 0; i < nr_cpus; i++) {
1175 for (counter = 0; counter < nr_counters; counter++) 1201 list_for_each_entry(counter, &evsel_list, node) {
1176 for (thread_index = 0; 1202 for (thread_index = 0;
1177 thread_index < thread_num; 1203 thread_index < thread_num;
1178 thread_index++) { 1204 thread_index++) {
1179 perf_session__mmap_read_counter(self, 1205 perf_session__mmap_read_counter(self,
1180 &mmap_array[i][counter][thread_index]); 1206 counter, i, thread_index);
1181 } 1207 }
1208 }
1182 } 1209 }
1183} 1210}
1184 1211
1185int nr_poll; 1212int nr_poll;
1186int group_fd; 1213int group_fd;
1187 1214
1188static void start_counter(int i, int counter) 1215static void start_counter(int i, struct perf_evsel *evsel)
1189{ 1216{
1217 struct xyarray *mmap_array = evsel->priv;
1218 struct mmap_data *mm;
1190 struct perf_event_attr *attr; 1219 struct perf_event_attr *attr;
1191 int cpu = -1; 1220 int cpu = -1;
1192 int thread_index; 1221 int thread_index;
@@ -1194,7 +1223,7 @@ static void start_counter(int i, int counter)
1194 if (target_tid == -1) 1223 if (target_tid == -1)
1195 cpu = cpumap[i]; 1224 cpu = cpumap[i];
1196 1225
1197 attr = attrs + counter; 1226 attr = &evsel->attr;
1198 1227
1199 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1228 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1200 1229
@@ -1209,10 +1238,10 @@ static void start_counter(int i, int counter)
1209 1238
1210 for (thread_index = 0; thread_index < thread_num; thread_index++) { 1239 for (thread_index = 0; thread_index < thread_num; thread_index++) {
1211try_again: 1240try_again:
1212 fd[i][counter][thread_index] = sys_perf_event_open(attr, 1241 FD(evsel, i, thread_index) = sys_perf_event_open(attr,
1213 all_tids[thread_index], cpu, group_fd, 0); 1242 all_tids[thread_index], cpu, group_fd, 0);
1214 1243
1215 if (fd[i][counter][thread_index] < 0) { 1244 if (FD(evsel, i, thread_index) < 0) {
1216 int err = errno; 1245 int err = errno;
1217 1246
1218 if (err == EPERM || err == EACCES) 1247 if (err == EPERM || err == EACCES)
@@ -1236,29 +1265,29 @@ try_again:
1236 } 1265 }
1237 printf("\n"); 1266 printf("\n");
1238 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 1267 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
1239 fd[i][counter][thread_index], strerror(err)); 1268 FD(evsel, i, thread_index), strerror(err));
1240 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 1269 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1241 exit(-1); 1270 exit(-1);
1242 } 1271 }
1243 assert(fd[i][counter][thread_index] >= 0); 1272 assert(FD(evsel, i, thread_index) >= 0);
1244 fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK); 1273 fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
1245 1274
1246 /* 1275 /*
1247 * First counter acts as the group leader: 1276 * First counter acts as the group leader:
1248 */ 1277 */
1249 if (group && group_fd == -1) 1278 if (group && group_fd == -1)
1250 group_fd = fd[i][counter][thread_index]; 1279 group_fd = FD(evsel, i, thread_index);
1251 1280
1252 event_array[nr_poll].fd = fd[i][counter][thread_index]; 1281 event_array[nr_poll].fd = FD(evsel, i, thread_index);
1253 event_array[nr_poll].events = POLLIN; 1282 event_array[nr_poll].events = POLLIN;
1254 nr_poll++; 1283 nr_poll++;
1255 1284
1256 mmap_array[i][counter][thread_index].counter = counter; 1285 mm = xyarray__entry(mmap_array, i, thread_index);
1257 mmap_array[i][counter][thread_index].prev = 0; 1286 mm->prev = 0;
1258 mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1; 1287 mm->mask = mmap_pages*page_size - 1;
1259 mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, 1288 mm->base = mmap(NULL, (mmap_pages+1)*page_size,
1260 PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0); 1289 PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
1261 if (mmap_array[i][counter][thread_index].base == MAP_FAILED) 1290 if (mm->base == MAP_FAILED)
1262 die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 1291 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1263 } 1292 }
1264} 1293}
@@ -1266,8 +1295,8 @@ try_again:
1266static int __cmd_top(void) 1295static int __cmd_top(void)
1267{ 1296{
1268 pthread_t thread; 1297 pthread_t thread;
1269 int i, counter; 1298 struct perf_evsel *counter;
1270 int ret; 1299 int i, ret;
1271 /* 1300 /*
1272 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 1301 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1273 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 1302 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -1283,7 +1312,7 @@ static int __cmd_top(void)
1283 1312
1284 for (i = 0; i < nr_cpus; i++) { 1313 for (i = 0; i < nr_cpus; i++) {
1285 group_fd = -1; 1314 group_fd = -1;
1286 for (counter = 0; counter < nr_counters; counter++) 1315 list_for_each_entry(counter, &evsel_list, node)
1287 start_counter(i, counter); 1316 start_counter(i, counter);
1288 } 1317 }
1289 1318
@@ -1372,8 +1401,8 @@ static const struct option options[] = {
1372 1401
1373int cmd_top(int argc, const char **argv, const char *prefix __used) 1402int cmd_top(int argc, const char **argv, const char *prefix __used)
1374{ 1403{
1375 int counter; 1404 struct perf_evsel *pos;
1376 int i,j; 1405 int status = -ENOMEM;
1377 1406
1378 page_size = sysconf(_SC_PAGE_SIZE); 1407 page_size = sysconf(_SC_PAGE_SIZE);
1379 1408
@@ -1398,15 +1427,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1398 thread_num = 1; 1427 thread_num = 1;
1399 } 1428 }
1400 1429
1401 for (i = 0; i < MAX_NR_CPUS; i++) {
1402 for (j = 0; j < MAX_COUNTERS; j++) {
1403 fd[i][j] = malloc(sizeof(int)*thread_num);
1404 mmap_array[i][j] = zalloc(
1405 sizeof(struct mmap_data)*thread_num);
1406 if (!fd[i][j] || !mmap_array[i][j])
1407 return -ENOMEM;
1408 }
1409 }
1410 event_array = malloc( 1430 event_array = malloc(
1411 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); 1431 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
1412 if (!event_array) 1432 if (!event_array)
@@ -1419,15 +1439,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1419 cpu_list = NULL; 1439 cpu_list = NULL;
1420 } 1440 }
1421 1441
1422 if (!nr_counters) 1442 if (!nr_counters && perf_evsel_list__create_default() < 0) {
1423 nr_counters = 1; 1443 pr_err("Not enough memory for event selector list\n");
1424 1444 return -ENOMEM;
1425 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1445 }
1426 (nr_counters + 1) * sizeof(unsigned long));
1427
1428 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1429 if (symbol__init() < 0)
1430 return -1;
1431 1446
1432 if (delay_secs < 1) 1447 if (delay_secs < 1)
1433 delay_secs = 1; 1448 delay_secs = 1;
@@ -1444,16 +1459,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1444 exit(EXIT_FAILURE); 1459 exit(EXIT_FAILURE);
1445 } 1460 }
1446 1461
1447 /*
1448 * Fill in the ones not specifically initialized via -c:
1449 */
1450 for (counter = 0; counter < nr_counters; counter++) {
1451 if (attrs[counter].sample_period)
1452 continue;
1453
1454 attrs[counter].sample_period = default_interval;
1455 }
1456
1457 if (target_tid != -1) 1462 if (target_tid != -1)
1458 nr_cpus = 1; 1463 nr_cpus = 1;
1459 else 1464 else
@@ -1462,11 +1467,38 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1462 if (nr_cpus < 1) 1467 if (nr_cpus < 1)
1463 usage_with_options(top_usage, options); 1468 usage_with_options(top_usage, options);
1464 1469
1470 list_for_each_entry(pos, &evsel_list, node) {
1471 if (perf_evsel__alloc_mmap_per_thread(pos, nr_cpus, thread_num) < 0 ||
1472 perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0)
1473 goto out_free_fd;
1474 /*
1475 * Fill in the ones not specifically initialized via -c:
1476 */
1477 if (pos->attr.sample_period)
1478 continue;
1479
1480 pos->attr.sample_period = default_interval;
1481 }
1482
1483 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1484 (nr_counters + 1) * sizeof(unsigned long));
1485
1486 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1487 if (symbol__init() < 0)
1488 return -1;
1489
1465 get_term_dimensions(&winsize); 1490 get_term_dimensions(&winsize);
1466 if (print_entries == 0) { 1491 if (print_entries == 0) {
1467 update_print_entries(&winsize); 1492 update_print_entries(&winsize);
1468 signal(SIGWINCH, sig_winch_handler); 1493 signal(SIGWINCH, sig_winch_handler);
1469 } 1494 }
1470 1495
1471 return __cmd_top(); 1496 status = __cmd_top();
1497out_free_fd:
1498 list_for_each_entry(pos, &evsel_list, node) {
1499 perf_evsel__free_fd(pos);
1500 perf_evsel__free_mmap(pos);
1501 }
1502
1503 return status;
1472} 1504}