diff options
author | Mike Galbraith <efault@gmx.de> | 2009-03-27 07:13:43 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-04-06 03:30:44 -0400 |
commit | 9dd499889bdb12ac0e412ccdd718fe0d348258f2 (patch) | |
tree | c3c74684dac1e32aaf413c81e94d0dd15a154199 /Documentation/perf_counter | |
parent | 4e935e47177c3b26cf383e79849bae2a464d0160 (diff) |
perf_counter tools: kerneltop: add real-time data acquisition thread
Decouple kerneltop display from event acquisition by introducing
a separate data acquisition thread. This fixes annnoying kerneltop
display refresh jitter and missed events.
Also add a -r <prio> option, to switch the data acquisition thread
to real-time priority.
Signed-off-by: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Orig-LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation/perf_counter')
-rw-r--r-- | Documentation/perf_counter/kerneltop.c | 57 |
1 files changed, 39 insertions, 18 deletions
diff --git a/Documentation/perf_counter/kerneltop.c b/Documentation/perf_counter/kerneltop.c index 430810dae1fe..33b4fcf6e489 100644 --- a/Documentation/perf_counter/kerneltop.c +++ b/Documentation/perf_counter/kerneltop.c | |||
@@ -77,6 +77,8 @@ | |||
77 | #include <errno.h> | 77 | #include <errno.h> |
78 | #include <ctype.h> | 78 | #include <ctype.h> |
79 | #include <time.h> | 79 | #include <time.h> |
80 | #include <sched.h> | ||
81 | #include <pthread.h> | ||
80 | 82 | ||
81 | #include <sys/syscall.h> | 83 | #include <sys/syscall.h> |
82 | #include <sys/ioctl.h> | 84 | #include <sys/ioctl.h> |
@@ -181,6 +183,7 @@ static int tid = -1; | |||
181 | static int profile_cpu = -1; | 183 | static int profile_cpu = -1; |
182 | static int nr_cpus = 0; | 184 | static int nr_cpus = 0; |
183 | static int nmi = 1; | 185 | static int nmi = 1; |
186 | static unsigned int realtime_prio = 0; | ||
184 | static int group = 0; | 187 | static int group = 0; |
185 | static unsigned int page_size; | 188 | static unsigned int page_size; |
186 | static unsigned int mmap_pages = 16; | 189 | static unsigned int mmap_pages = 16; |
@@ -334,6 +337,7 @@ static void display_help(void) | |||
334 | " -l # show scale factor for RR events\n" | 337 | " -l # show scale factor for RR events\n" |
335 | " -d delay --delay=<seconds> # sampling/display delay [default: 2]\n" | 338 | " -d delay --delay=<seconds> # sampling/display delay [default: 2]\n" |
336 | " -f CNT --filter=CNT # min-event-count filter [default: 100]\n\n" | 339 | " -f CNT --filter=CNT # min-event-count filter [default: 100]\n\n" |
340 | " -r prio --realtime=<prio> # event acquisition runs with SCHED_FIFO policy\n" | ||
337 | " -s symbol --symbol=<symbol> # function to be showed annotated one-shot\n" | 341 | " -s symbol --symbol=<symbol> # function to be showed annotated one-shot\n" |
338 | " -x path --vmlinux=<path> # the vmlinux binary, required for -s use\n" | 342 | " -x path --vmlinux=<path> # the vmlinux binary, required for -s use\n" |
339 | " -z --zero # zero counts after display\n" | 343 | " -z --zero # zero counts after display\n" |
@@ -620,7 +624,6 @@ static int compare(const void *__sym1, const void *__sym2) | |||
620 | return sym_weight(sym1) < sym_weight(sym2); | 624 | return sym_weight(sym1) < sym_weight(sym2); |
621 | } | 625 | } |
622 | 626 | ||
623 | static time_t last_refresh; | ||
624 | static long events; | 627 | static long events; |
625 | static long userspace_events; | 628 | static long userspace_events; |
626 | static const char CONSOLE_CLEAR[] = "[H[2J"; | 629 | static const char CONSOLE_CLEAR[] = "[H[2J"; |
@@ -634,6 +637,7 @@ static void print_sym_table(void) | |||
634 | float events_per_sec = events/delay_secs; | 637 | float events_per_sec = events/delay_secs; |
635 | float kevents_per_sec = (events-userspace_events)/delay_secs; | 638 | float kevents_per_sec = (events-userspace_events)/delay_secs; |
636 | 639 | ||
640 | events = userspace_events = 0; | ||
637 | memcpy(tmp, sym_table, sizeof(sym_table[0])*sym_table_count); | 641 | memcpy(tmp, sym_table, sizeof(sym_table[0])*sym_table_count); |
638 | qsort(tmp, sym_table_count, sizeof(tmp[0]), compare); | 642 | qsort(tmp, sym_table_count, sizeof(tmp[0]), compare); |
639 | 643 | ||
@@ -714,8 +718,6 @@ static void print_sym_table(void) | |||
714 | if (sym_filter_entry) | 718 | if (sym_filter_entry) |
715 | show_details(sym_filter_entry); | 719 | show_details(sym_filter_entry); |
716 | 720 | ||
717 | last_refresh = time(NULL); | ||
718 | |||
719 | { | 721 | { |
720 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 722 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
721 | 723 | ||
@@ -726,6 +728,16 @@ static void print_sym_table(void) | |||
726 | } | 728 | } |
727 | } | 729 | } |
728 | 730 | ||
731 | static void *display_thread(void *arg) | ||
732 | { | ||
733 | printf("KernelTop refresh period: %d seconds\n", delay_secs); | ||
734 | |||
735 | while (!sleep(delay_secs)) | ||
736 | print_sym_table(); | ||
737 | |||
738 | return NULL; | ||
739 | } | ||
740 | |||
729 | static int read_symbol(FILE *in, struct sym_entry *s) | 741 | static int read_symbol(FILE *in, struct sym_entry *s) |
730 | { | 742 | { |
731 | static int filter_match = 0; | 743 | static int filter_match = 0; |
@@ -1081,19 +1093,20 @@ static void process_options(int argc, char *argv[]) | |||
1081 | {"filter", required_argument, NULL, 'f'}, | 1093 | {"filter", required_argument, NULL, 'f'}, |
1082 | {"group", required_argument, NULL, 'g'}, | 1094 | {"group", required_argument, NULL, 'g'}, |
1083 | {"help", no_argument, NULL, 'h'}, | 1095 | {"help", no_argument, NULL, 'h'}, |
1084 | {"scale", no_argument, NULL, 'l'}, | ||
1085 | {"nmi", required_argument, NULL, 'n'}, | 1096 | {"nmi", required_argument, NULL, 'n'}, |
1097 | {"mmap_info", no_argument, NULL, 'M'}, | ||
1098 | {"mmap_pages", required_argument, NULL, 'm'}, | ||
1099 | {"munmap_info", no_argument, NULL, 'U'}, | ||
1086 | {"pid", required_argument, NULL, 'p'}, | 1100 | {"pid", required_argument, NULL, 'p'}, |
1087 | {"vmlinux", required_argument, NULL, 'x'}, | 1101 | {"realtime", required_argument, NULL, 'r'}, |
1102 | {"scale", no_argument, NULL, 'l'}, | ||
1088 | {"symbol", required_argument, NULL, 's'}, | 1103 | {"symbol", required_argument, NULL, 's'}, |
1089 | {"stat", no_argument, NULL, 'S'}, | 1104 | {"stat", no_argument, NULL, 'S'}, |
1105 | {"vmlinux", required_argument, NULL, 'x'}, | ||
1090 | {"zero", no_argument, NULL, 'z'}, | 1106 | {"zero", no_argument, NULL, 'z'}, |
1091 | {"mmap_pages", required_argument, NULL, 'm'}, | ||
1092 | {"mmap_info", no_argument, NULL, 'M'}, | ||
1093 | {"munmap_info", no_argument, NULL, 'U'}, | ||
1094 | {NULL, 0, NULL, 0 } | 1107 | {NULL, 0, NULL, 0 } |
1095 | }; | 1108 | }; |
1096 | int c = getopt_long(argc, argv, "+:ac:C:d:De:f:g:hln:m:p:s:Sx:zMU", | 1109 | int c = getopt_long(argc, argv, "+:ac:C:d:De:f:g:hln:m:p:r:s:Sx:zMU", |
1097 | long_options, &option_index); | 1110 | long_options, &option_index); |
1098 | if (c == -1) | 1111 | if (c == -1) |
1099 | break; | 1112 | break; |
@@ -1127,6 +1140,7 @@ static void process_options(int argc, char *argv[]) | |||
1127 | profile_cpu = -1; | 1140 | profile_cpu = -1; |
1128 | } | 1141 | } |
1129 | tid = atoi(optarg); break; | 1142 | tid = atoi(optarg); break; |
1143 | case 'r': realtime_prio = atoi(optarg); break; | ||
1130 | case 's': sym_filter = strdup(optarg); break; | 1144 | case 's': sym_filter = strdup(optarg); break; |
1131 | case 'S': run_perfstat = 1; break; | 1145 | case 'S': run_perfstat = 1; break; |
1132 | case 'x': vmlinux = strdup(optarg); break; | 1146 | case 'x': vmlinux = strdup(optarg); break; |
@@ -1289,6 +1303,7 @@ int main(int argc, char *argv[]) | |||
1289 | struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; | 1303 | struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; |
1290 | struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | 1304 | struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; |
1291 | struct perf_counter_hw_event hw_event; | 1305 | struct perf_counter_hw_event hw_event; |
1306 | pthread_t thread; | ||
1292 | int i, counter, group_fd, nr_poll = 0; | 1307 | int i, counter, group_fd, nr_poll = 0; |
1293 | unsigned int cpu; | 1308 | unsigned int cpu; |
1294 | int ret; | 1309 | int ret; |
@@ -1363,8 +1378,20 @@ int main(int argc, char *argv[]) | |||
1363 | } | 1378 | } |
1364 | } | 1379 | } |
1365 | 1380 | ||
1366 | printf("KernelTop refresh period: %d seconds\n", delay_secs); | 1381 | if (pthread_create(&thread, NULL, display_thread, NULL)) { |
1367 | last_refresh = time(NULL); | 1382 | printf("Could not create display thread.\n"); |
1383 | exit(-1); | ||
1384 | } | ||
1385 | |||
1386 | if (realtime_prio) { | ||
1387 | struct sched_param param; | ||
1388 | |||
1389 | param.sched_priority = realtime_prio; | ||
1390 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | ||
1391 | printf("Could not set realtime priority.\n"); | ||
1392 | exit(-1); | ||
1393 | } | ||
1394 | } | ||
1368 | 1395 | ||
1369 | while (1) { | 1396 | while (1) { |
1370 | int hits = events; | 1397 | int hits = events; |
@@ -1374,14 +1401,8 @@ int main(int argc, char *argv[]) | |||
1374 | mmap_read(&mmap_array[i][counter]); | 1401 | mmap_read(&mmap_array[i][counter]); |
1375 | } | 1402 | } |
1376 | 1403 | ||
1377 | if (time(NULL) >= last_refresh + delay_secs) { | ||
1378 | print_sym_table(); | ||
1379 | events = userspace_events = 0; | ||
1380 | } | ||
1381 | |||
1382 | if (hits == events) | 1404 | if (hits == events) |
1383 | ret = poll(event_array, nr_poll, 1000); | 1405 | ret = poll(event_array, nr_poll, 100); |
1384 | hits = events; | ||
1385 | } | 1406 | } |
1386 | 1407 | ||
1387 | return 0; | 1408 | return 0; |