aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c290
1 files changed, 204 insertions, 86 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 1f529321607e..dfd7ea7dabdd 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -55,9 +55,9 @@
55#include <linux/unistd.h> 55#include <linux/unistd.h>
56#include <linux/types.h> 56#include <linux/types.h>
57 57
58static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 58static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
59 59
60static int system_wide = 0; 60static bool system_wide = false;
61 61
62static int default_interval = 0; 62static int default_interval = 0;
63 63
@@ -65,18 +65,21 @@ static int count_filter = 5;
65static int print_entries; 65static int print_entries;
66 66
67static int target_pid = -1; 67static int target_pid = -1;
68static int inherit = 0; 68static int target_tid = -1;
69static pid_t *all_tids = NULL;
70static int thread_num = 0;
71static bool inherit = false;
69static int profile_cpu = -1; 72static int profile_cpu = -1;
70static int nr_cpus = 0; 73static int nr_cpus = 0;
71static unsigned int realtime_prio = 0; 74static unsigned int realtime_prio = 0;
72static int group = 0; 75static bool group = false;
73static unsigned int page_size; 76static unsigned int page_size;
74static unsigned int mmap_pages = 16; 77static unsigned int mmap_pages = 16;
75static int freq = 1000; /* 1 KHz */ 78static int freq = 1000; /* 1 KHz */
76 79
77static int delay_secs = 2; 80static int delay_secs = 2;
78static int zero = 0; 81static bool zero = false;
79static int dump_symtab = 0; 82static bool dump_symtab = false;
80 83
81static bool hide_kernel_symbols = false; 84static bool hide_kernel_symbols = false;
82static bool hide_user_symbols = false; 85static bool hide_user_symbols = false;
@@ -133,7 +136,7 @@ static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
133 return ((void *)self) + symbol_conf.priv_size; 136 return ((void *)self) + symbol_conf.priv_size;
134} 137}
135 138
136static void get_term_dimensions(struct winsize *ws) 139void get_term_dimensions(struct winsize *ws)
137{ 140{
138 char *s = getenv("LINES"); 141 char *s = getenv("LINES");
139 142
@@ -169,7 +172,7 @@ static void sig_winch_handler(int sig __used)
169 update_print_entries(&winsize); 172 update_print_entries(&winsize);
170} 173}
171 174
172static void parse_source(struct sym_entry *syme) 175static int parse_source(struct sym_entry *syme)
173{ 176{
174 struct symbol *sym; 177 struct symbol *sym;
175 struct sym_entry_source *source; 178 struct sym_entry_source *source;
@@ -180,12 +183,21 @@ static void parse_source(struct sym_entry *syme)
180 u64 len; 183 u64 len;
181 184
182 if (!syme) 185 if (!syme)
183 return; 186 return -1;
187
188 sym = sym_entry__symbol(syme);
189 map = syme->map;
190
191 /*
192 * We can't annotate with just /proc/kallsyms
193 */
194 if (map->dso->origin == DSO__ORIG_KERNEL)
195 return -1;
184 196
185 if (syme->src == NULL) { 197 if (syme->src == NULL) {
186 syme->src = zalloc(sizeof(*source)); 198 syme->src = zalloc(sizeof(*source));
187 if (syme->src == NULL) 199 if (syme->src == NULL)
188 return; 200 return -1;
189 pthread_mutex_init(&syme->src->lock, NULL); 201 pthread_mutex_init(&syme->src->lock, NULL);
190 } 202 }
191 203
@@ -195,9 +207,6 @@ static void parse_source(struct sym_entry *syme)
195 pthread_mutex_lock(&source->lock); 207 pthread_mutex_lock(&source->lock);
196 goto out_assign; 208 goto out_assign;
197 } 209 }
198
199 sym = sym_entry__symbol(syme);
200 map = syme->map;
201 path = map->dso->long_name; 210 path = map->dso->long_name;
202 211
203 len = sym->end - sym->start; 212 len = sym->end - sym->start;
@@ -209,7 +218,7 @@ static void parse_source(struct sym_entry *syme)
209 218
210 file = popen(command, "r"); 219 file = popen(command, "r");
211 if (!file) 220 if (!file)
212 return; 221 return -1;
213 222
214 pthread_mutex_lock(&source->lock); 223 pthread_mutex_lock(&source->lock);
215 source->lines_tail = &source->lines; 224 source->lines_tail = &source->lines;
@@ -245,6 +254,7 @@ static void parse_source(struct sym_entry *syme)
245out_assign: 254out_assign:
246 sym_filter_entry = syme; 255 sym_filter_entry = syme;
247 pthread_mutex_unlock(&source->lock); 256 pthread_mutex_unlock(&source->lock);
257 return 0;
248} 258}
249 259
250static void __zero_source_counters(struct sym_entry *syme) 260static void __zero_source_counters(struct sym_entry *syme)
@@ -410,7 +420,9 @@ static double sym_weight(const struct sym_entry *sym)
410} 420}
411 421
412static long samples; 422static long samples;
413static long userspace_samples; 423static long kernel_samples, us_samples;
424static long exact_samples;
425static long guest_us_samples, guest_kernel_samples;
414static const char CONSOLE_CLEAR[] = ""; 426static const char CONSOLE_CLEAR[] = "";
415 427
416static void __list_insert_active_sym(struct sym_entry *syme) 428static void __list_insert_active_sym(struct sym_entry *syme)
@@ -450,7 +462,11 @@ static void print_sym_table(void)
450 int printed = 0, j; 462 int printed = 0, j;
451 int counter, snap = !display_weighted ? sym_counter : 0; 463 int counter, snap = !display_weighted ? sym_counter : 0;
452 float samples_per_sec = samples/delay_secs; 464 float samples_per_sec = samples/delay_secs;
453 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 465 float ksamples_per_sec = kernel_samples/delay_secs;
466 float us_samples_per_sec = (us_samples)/delay_secs;
467 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
468 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
469 float esamples_percent = (100.0*exact_samples)/samples;
454 float sum_ksamples = 0.0; 470 float sum_ksamples = 0.0;
455 struct sym_entry *syme, *n; 471 struct sym_entry *syme, *n;
456 struct rb_root tmp = RB_ROOT; 472 struct rb_root tmp = RB_ROOT;
@@ -458,7 +474,8 @@ static void print_sym_table(void)
458 int sym_width = 0, dso_width = 0, dso_short_width = 0; 474 int sym_width = 0, dso_width = 0, dso_short_width = 0;
459 const int win_width = winsize.ws_col - 1; 475 const int win_width = winsize.ws_col - 1;
460 476
461 samples = userspace_samples = 0; 477 samples = us_samples = kernel_samples = exact_samples = 0;
478 guest_kernel_samples = guest_us_samples = 0;
462 479
463 /* Sort the active symbols */ 480 /* Sort the active symbols */
464 pthread_mutex_lock(&active_symbols_lock); 481 pthread_mutex_lock(&active_symbols_lock);
@@ -489,9 +506,30 @@ static void print_sym_table(void)
489 puts(CONSOLE_CLEAR); 506 puts(CONSOLE_CLEAR);
490 507
491 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 508 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
492 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 509 if (!perf_guest) {
493 samples_per_sec, 510 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
494 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 511 " exact: %4.1f%% [",
512 samples_per_sec,
513 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
514 samples_per_sec)),
515 esamples_percent);
516 } else {
517 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
518 " guest kernel:%4.1f%% guest us:%4.1f%%"
519 " exact: %4.1f%% [",
520 samples_per_sec,
521 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
522 samples_per_sec)),
523 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
524 samples_per_sec)),
525 100.0 - (100.0 * ((samples_per_sec -
526 guest_kernel_samples_per_sec) /
527 samples_per_sec)),
528 100.0 - (100.0 * ((samples_per_sec -
529 guest_us_samples_per_sec) /
530 samples_per_sec)),
531 esamples_percent);
532 }
495 533
496 if (nr_counters == 1 || !display_weighted) { 534 if (nr_counters == 1 || !display_weighted) {
497 printf("%Ld", (u64)attrs[0].sample_period); 535 printf("%Ld", (u64)attrs[0].sample_period);
@@ -514,13 +552,15 @@ static void print_sym_table(void)
514 552
515 if (target_pid != -1) 553 if (target_pid != -1)
516 printf(" (target_pid: %d", target_pid); 554 printf(" (target_pid: %d", target_pid);
555 else if (target_tid != -1)
556 printf(" (target_tid: %d", target_tid);
517 else 557 else
518 printf(" (all"); 558 printf(" (all");
519 559
520 if (profile_cpu != -1) 560 if (profile_cpu != -1)
521 printf(", cpu: %d)\n", profile_cpu); 561 printf(", cpu: %d)\n", profile_cpu);
522 else { 562 else {
523 if (target_pid != -1) 563 if (target_tid != -1)
524 printf(")\n"); 564 printf(")\n");
525 else 565 else
526 printf(", %d CPUs)\n", nr_cpus); 566 printf(", %d CPUs)\n", nr_cpus);
@@ -582,7 +622,6 @@ static void print_sym_table(void)
582 622
583 syme = rb_entry(nd, struct sym_entry, rb_node); 623 syme = rb_entry(nd, struct sym_entry, rb_node);
584 sym = sym_entry__symbol(syme); 624 sym = sym_entry__symbol(syme);
585
586 if (++printed > print_entries || (int)syme->snap_count < count_filter) 625 if (++printed > print_entries || (int)syme->snap_count < count_filter)
587 continue; 626 continue;
588 627
@@ -746,7 +785,7 @@ static int key_mapped(int c)
746 return 0; 785 return 0;
747} 786}
748 787
749static void handle_keypress(int c) 788static void handle_keypress(struct perf_session *session, int c)
750{ 789{
751 if (!key_mapped(c)) { 790 if (!key_mapped(c)) {
752 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 791 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -815,7 +854,7 @@ static void handle_keypress(int c)
815 case 'Q': 854 case 'Q':
816 printf("exiting.\n"); 855 printf("exiting.\n");
817 if (dump_symtab) 856 if (dump_symtab)
818 dsos__fprintf(stderr); 857 dsos__fprintf(&session->kerninfo_root, stderr);
819 exit(0); 858 exit(0);
820 case 's': 859 case 's':
821 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 860 prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -839,7 +878,7 @@ static void handle_keypress(int c)
839 display_weighted = ~display_weighted; 878 display_weighted = ~display_weighted;
840 break; 879 break;
841 case 'z': 880 case 'z':
842 zero = ~zero; 881 zero = !zero;
843 break; 882 break;
844 default: 883 default:
845 break; 884 break;
@@ -851,6 +890,7 @@ static void *display_thread(void *arg __used)
851 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 890 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
852 struct termios tc, save; 891 struct termios tc, save;
853 int delay_msecs, c; 892 int delay_msecs, c;
893 struct perf_session *session = (struct perf_session *) arg;
854 894
855 tcgetattr(0, &save); 895 tcgetattr(0, &save);
856 tc = save; 896 tc = save;
@@ -871,7 +911,7 @@ repeat:
871 c = getc(stdin); 911 c = getc(stdin);
872 tcsetattr(0, TCSAFLUSH, &save); 912 tcsetattr(0, TCSAFLUSH, &save);
873 913
874 handle_keypress(c); 914 handle_keypress(session, c);
875 goto repeat; 915 goto repeat;
876 916
877 return NULL; 917 return NULL;
@@ -942,24 +982,49 @@ static void event__process_sample(const event_t *self,
942 u64 ip = self->ip.ip; 982 u64 ip = self->ip.ip;
943 struct sym_entry *syme; 983 struct sym_entry *syme;
944 struct addr_location al; 984 struct addr_location al;
985 struct kernel_info *kerninfo;
945 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 986 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
946 987
947 ++samples; 988 ++samples;
948 989
949 switch (origin) { 990 switch (origin) {
950 case PERF_RECORD_MISC_USER: 991 case PERF_RECORD_MISC_USER:
951 ++userspace_samples; 992 ++us_samples;
952 if (hide_user_symbols) 993 if (hide_user_symbols)
953 return; 994 return;
995 kerninfo = kerninfo__findhost(&session->kerninfo_root);
954 break; 996 break;
955 case PERF_RECORD_MISC_KERNEL: 997 case PERF_RECORD_MISC_KERNEL:
998 ++kernel_samples;
956 if (hide_kernel_symbols) 999 if (hide_kernel_symbols)
957 return; 1000 return;
1001 kerninfo = kerninfo__findhost(&session->kerninfo_root);
1002 break;
1003 case PERF_RECORD_MISC_GUEST_KERNEL:
1004 ++guest_kernel_samples;
1005 kerninfo = kerninfo__find(&session->kerninfo_root,
1006 self->ip.pid);
958 break; 1007 break;
1008 case PERF_RECORD_MISC_GUEST_USER:
1009 ++guest_us_samples;
1010 /*
1011 * TODO: we don't process guest user from host side
1012 * except simple counting.
1013 */
1014 return;
959 default: 1015 default:
960 return; 1016 return;
961 } 1017 }
962 1018
1019 if (!kerninfo && perf_guest) {
1020 pr_err("Can't find guest [%d]'s kernel information\n",
1021 self->ip.pid);
1022 return;
1023 }
1024
1025 if (self->header.misc & PERF_RECORD_MISC_EXACT)
1026 exact_samples++;
1027
963 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || 1028 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
964 al.filtered) 1029 al.filtered)
965 return; 1030 return;
@@ -976,7 +1041,7 @@ static void event__process_sample(const event_t *self,
976 * --hide-kernel-symbols, even if the user specifies an 1041 * --hide-kernel-symbols, even if the user specifies an
977 * invalid --vmlinux ;-) 1042 * invalid --vmlinux ;-)
978 */ 1043 */
979 if (al.map == session->vmlinux_maps[MAP__FUNCTION] && 1044 if (al.map == kerninfo->vmlinux_maps[MAP__FUNCTION] &&
980 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 1045 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
981 pr_err("The %s file can't be used\n", 1046 pr_err("The %s file can't be used\n",
982 symbol_conf.vmlinux_name); 1047 symbol_conf.vmlinux_name);
@@ -990,7 +1055,17 @@ static void event__process_sample(const event_t *self,
990 if (sym_filter_entry_sched) { 1055 if (sym_filter_entry_sched) {
991 sym_filter_entry = sym_filter_entry_sched; 1056 sym_filter_entry = sym_filter_entry_sched;
992 sym_filter_entry_sched = NULL; 1057 sym_filter_entry_sched = NULL;
993 parse_source(sym_filter_entry); 1058 if (parse_source(sym_filter_entry) < 0) {
1059 struct symbol *sym = sym_entry__symbol(sym_filter_entry);
1060
1061 pr_err("Can't annotate %s", sym->name);
1062 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
1063 pr_err(": No vmlinux file was found in the path:\n");
1064 vmlinux_path__fprintf(stderr);
1065 } else
1066 pr_err(".\n");
1067 exit(1);
1068 }
994 } 1069 }
995 1070
996 syme = symbol__priv(al.sym); 1071 syme = symbol__priv(al.sym);
@@ -1106,16 +1181,21 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1106 md->prev = old; 1181 md->prev = old;
1107} 1182}
1108 1183
1109static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1184static struct pollfd *event_array;
1110static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1185static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1111 1186
1112static void perf_session__mmap_read(struct perf_session *self) 1187static void perf_session__mmap_read(struct perf_session *self)
1113{ 1188{
1114 int i, counter; 1189 int i, counter, thread_index;
1115 1190
1116 for (i = 0; i < nr_cpus; i++) { 1191 for (i = 0; i < nr_cpus; i++) {
1117 for (counter = 0; counter < nr_counters; counter++) 1192 for (counter = 0; counter < nr_counters; counter++)
1118 perf_session__mmap_read_counter(self, &mmap_array[i][counter]); 1193 for (thread_index = 0;
1194 thread_index < thread_num;
1195 thread_index++) {
1196 perf_session__mmap_read_counter(self,
1197 &mmap_array[i][counter][thread_index]);
1198 }
1119 } 1199 }
1120} 1200}
1121 1201
@@ -1126,9 +1206,10 @@ static void start_counter(int i, int counter)
1126{ 1206{
1127 struct perf_event_attr *attr; 1207 struct perf_event_attr *attr;
1128 int cpu; 1208 int cpu;
1209 int thread_index;
1129 1210
1130 cpu = profile_cpu; 1211 cpu = profile_cpu;
1131 if (target_pid == -1 && profile_cpu == -1) 1212 if (target_tid == -1 && profile_cpu == -1)
1132 cpu = cpumap[i]; 1213 cpu = cpumap[i];
1133 1214
1134 attr = attrs + counter; 1215 attr = attrs + counter;
@@ -1144,55 +1225,58 @@ static void start_counter(int i, int counter)
1144 attr->inherit = (cpu < 0) && inherit; 1225 attr->inherit = (cpu < 0) && inherit;
1145 attr->mmap = 1; 1226 attr->mmap = 1;
1146 1227
1228 for (thread_index = 0; thread_index < thread_num; thread_index++) {
1147try_again: 1229try_again:
1148 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1230 fd[i][counter][thread_index] = sys_perf_event_open(attr,
1149 1231 all_tids[thread_index], cpu, group_fd, 0);
1150 if (fd[i][counter] < 0) { 1232
1151 int err = errno; 1233 if (fd[i][counter][thread_index] < 0) {
1234 int err = errno;
1235
1236 if (err == EPERM || err == EACCES)
1237 die("No permission - are you root?\n");
1238 /*
1239 * If it's cycles then fall back to hrtimer
1240 * based cpu-clock-tick sw counter, which
1241 * is always available even if no PMU support:
1242 */
1243 if (attr->type == PERF_TYPE_HARDWARE
1244 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1245
1246 if (verbose)
1247 warning(" ... trying to fall back to cpu-clock-ticks\n");
1248
1249 attr->type = PERF_TYPE_SOFTWARE;
1250 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1251 goto try_again;
1252 }
1253 printf("\n");
1254 error("perfcounter syscall returned with %d (%s)\n",
1255 fd[i][counter][thread_index], strerror(err));
1256 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1257 exit(-1);
1258 }
1259 assert(fd[i][counter][thread_index] >= 0);
1260 fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK);
1152 1261
1153 if (err == EPERM || err == EACCES)
1154 die("No permission - are you root?\n");
1155 /* 1262 /*
1156 * If it's cycles then fall back to hrtimer 1263 * First counter acts as the group leader:
1157 * based cpu-clock-tick sw counter, which
1158 * is always available even if no PMU support:
1159 */ 1264 */
1160 if (attr->type == PERF_TYPE_HARDWARE 1265 if (group && group_fd == -1)
1161 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 1266 group_fd = fd[i][counter][thread_index];
1162 1267
1163 if (verbose) 1268 event_array[nr_poll].fd = fd[i][counter][thread_index];
1164 warning(" ... trying to fall back to cpu-clock-ticks\n"); 1269 event_array[nr_poll].events = POLLIN;
1165 1270 nr_poll++;
1166 attr->type = PERF_TYPE_SOFTWARE; 1271
1167 attr->config = PERF_COUNT_SW_CPU_CLOCK; 1272 mmap_array[i][counter][thread_index].counter = counter;
1168 goto try_again; 1273 mmap_array[i][counter][thread_index].prev = 0;
1169 } 1274 mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1;
1170 printf("\n"); 1275 mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size,
1171 error("perfcounter syscall returned with %d (%s)\n", 1276 PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0);
1172 fd[i][counter], strerror(err)); 1277 if (mmap_array[i][counter][thread_index].base == MAP_FAILED)
1173 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 1278 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1174 exit(-1);
1175 } 1279 }
1176 assert(fd[i][counter] >= 0);
1177 fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
1178
1179 /*
1180 * First counter acts as the group leader:
1181 */
1182 if (group && group_fd == -1)
1183 group_fd = fd[i][counter];
1184
1185 event_array[nr_poll].fd = fd[i][counter];
1186 event_array[nr_poll].events = POLLIN;
1187 nr_poll++;
1188
1189 mmap_array[i][counter].counter = counter;
1190 mmap_array[i][counter].prev = 0;
1191 mmap_array[i][counter].mask = mmap_pages*page_size - 1;
1192 mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
1193 PROT_READ, MAP_SHARED, fd[i][counter], 0);
1194 if (mmap_array[i][counter].base == MAP_FAILED)
1195 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1196} 1280}
1197 1281
1198static int __cmd_top(void) 1282static int __cmd_top(void)
@@ -1208,8 +1292,8 @@ static int __cmd_top(void)
1208 if (session == NULL) 1292 if (session == NULL)
1209 return -ENOMEM; 1293 return -ENOMEM;
1210 1294
1211 if (target_pid != -1) 1295 if (target_tid != -1)
1212 event__synthesize_thread(target_pid, event__process, session); 1296 event__synthesize_thread(target_tid, event__process, session);
1213 else 1297 else
1214 event__synthesize_threads(event__process, session); 1298 event__synthesize_threads(event__process, session);
1215 1299
@@ -1220,11 +1304,11 @@ static int __cmd_top(void)
1220 } 1304 }
1221 1305
1222 /* Wait for a minimal set of events before starting the snapshot */ 1306 /* Wait for a minimal set of events before starting the snapshot */
1223 poll(event_array, nr_poll, 100); 1307 poll(&event_array[0], nr_poll, 100);
1224 1308
1225 perf_session__mmap_read(session); 1309 perf_session__mmap_read(session);
1226 1310
1227 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1311 if (pthread_create(&thread, NULL, display_thread, session)) {
1228 printf("Could not create display thread.\n"); 1312 printf("Could not create display thread.\n");
1229 exit(-1); 1313 exit(-1);
1230 } 1314 }
@@ -1263,7 +1347,9 @@ static const struct option options[] = {
1263 OPT_INTEGER('c', "count", &default_interval, 1347 OPT_INTEGER('c', "count", &default_interval,
1264 "event period to sample"), 1348 "event period to sample"),
1265 OPT_INTEGER('p', "pid", &target_pid, 1349 OPT_INTEGER('p', "pid", &target_pid,
1266 "profile events on existing pid"), 1350 "profile events on existing process id"),
1351 OPT_INTEGER('t', "tid", &target_tid,
1352 "profile events on existing thread id"),
1267 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1353 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1268 "system-wide collection from all CPUs"), 1354 "system-wide collection from all CPUs"),
1269 OPT_INTEGER('C', "CPU", &profile_cpu, 1355 OPT_INTEGER('C', "CPU", &profile_cpu,
@@ -1296,7 +1382,7 @@ static const struct option options[] = {
1296 "display this many functions"), 1382 "display this many functions"),
1297 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 1383 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1298 "hide user symbols"), 1384 "hide user symbols"),
1299 OPT_BOOLEAN('v', "verbose", &verbose, 1385 OPT_INCR('v', "verbose", &verbose,
1300 "be more verbose (show counter open errors, etc)"), 1386 "be more verbose (show counter open errors, etc)"),
1301 OPT_END() 1387 OPT_END()
1302}; 1388};
@@ -1304,6 +1390,7 @@ static const struct option options[] = {
1304int cmd_top(int argc, const char **argv, const char *prefix __used) 1390int cmd_top(int argc, const char **argv, const char *prefix __used)
1305{ 1391{
1306 int counter; 1392 int counter;
1393 int i,j;
1307 1394
1308 page_size = sysconf(_SC_PAGE_SIZE); 1395 page_size = sysconf(_SC_PAGE_SIZE);
1309 1396
@@ -1311,8 +1398,39 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1311 if (argc) 1398 if (argc)
1312 usage_with_options(top_usage, options); 1399 usage_with_options(top_usage, options);
1313 1400
1401 if (target_pid != -1) {
1402 target_tid = target_pid;
1403 thread_num = find_all_tid(target_pid, &all_tids);
1404 if (thread_num <= 0) {
1405 fprintf(stderr, "Can't find all threads of pid %d\n",
1406 target_pid);
1407 usage_with_options(top_usage, options);
1408 }
1409 } else {
1410 all_tids=malloc(sizeof(pid_t));
1411 if (!all_tids)
1412 return -ENOMEM;
1413
1414 all_tids[0] = target_tid;
1415 thread_num = 1;
1416 }
1417
1418 for (i = 0; i < MAX_NR_CPUS; i++) {
1419 for (j = 0; j < MAX_COUNTERS; j++) {
1420 fd[i][j] = malloc(sizeof(int)*thread_num);
1421 mmap_array[i][j] = zalloc(
1422 sizeof(struct mmap_data)*thread_num);
1423 if (!fd[i][j] || !mmap_array[i][j])
1424 return -ENOMEM;
1425 }
1426 }
1427 event_array = malloc(
1428 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
1429 if (!event_array)
1430 return -ENOMEM;
1431
1314 /* CPU and PID are mutually exclusive */ 1432 /* CPU and PID are mutually exclusive */
1315 if (target_pid != -1 && profile_cpu != -1) { 1433 if (target_tid > 0 && profile_cpu != -1) {
1316 printf("WARNING: PID switch overriding CPU\n"); 1434 printf("WARNING: PID switch overriding CPU\n");
1317 sleep(1); 1435 sleep(1);
1318 profile_cpu = -1; 1436 profile_cpu = -1;
@@ -1353,7 +1471,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1353 attrs[counter].sample_period = default_interval; 1471 attrs[counter].sample_period = default_interval;
1354 } 1472 }
1355 1473
1356 if (target_pid != -1 || profile_cpu != -1) 1474 if (target_tid != -1 || profile_cpu != -1)
1357 nr_cpus = 1; 1475 nr_cpus = 1;
1358 else 1476 else
1359 nr_cpus = read_cpu_map(); 1477 nr_cpus = read_cpu_map();