Commit 9dd49988 authored by Mike Galbraith's avatar Mike Galbraith Committed by Ingo Molnar

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: default avatarMike 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: default avatarIngo Molnar <mingo@elte.hu>
parent 4e935e47
...@@ -77,6 +77,8 @@ ...@@ -77,6 +77,8 @@
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <sched.h>
#include <pthread.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
...@@ -181,6 +183,7 @@ static int tid = -1; ...@@ -181,6 +183,7 @@ static int tid = -1;
static int profile_cpu = -1; static int profile_cpu = -1;
static int nr_cpus = 0; static int nr_cpus = 0;
static int nmi = 1; static int nmi = 1;
static unsigned int realtime_prio = 0;
static int group = 0; static int group = 0;
static unsigned int page_size; static unsigned int page_size;
static unsigned int mmap_pages = 16; static unsigned int mmap_pages = 16;
...@@ -334,6 +337,7 @@ static void display_help(void) ...@@ -334,6 +337,7 @@ static void display_help(void)
" -l # show scale factor for RR events\n" " -l # show scale factor for RR events\n"
" -d delay --delay=<seconds> # sampling/display delay [default: 2]\n" " -d delay --delay=<seconds> # sampling/display delay [default: 2]\n"
" -f CNT --filter=CNT # min-event-count filter [default: 100]\n\n" " -f CNT --filter=CNT # min-event-count filter [default: 100]\n\n"
" -r prio --realtime=<prio> # event acquisition runs with SCHED_FIFO policy\n"
" -s symbol --symbol=<symbol> # function to be showed annotated one-shot\n" " -s symbol --symbol=<symbol> # function to be showed annotated one-shot\n"
" -x path --vmlinux=<path> # the vmlinux binary, required for -s use\n" " -x path --vmlinux=<path> # the vmlinux binary, required for -s use\n"
" -z --zero # zero counts after display\n" " -z --zero # zero counts after display\n"
...@@ -620,7 +624,6 @@ static int compare(const void *__sym1, const void *__sym2) ...@@ -620,7 +624,6 @@ static int compare(const void *__sym1, const void *__sym2)
return sym_weight(sym1) < sym_weight(sym2); return sym_weight(sym1) < sym_weight(sym2);
} }
static time_t last_refresh;
static long events; static long events;
static long userspace_events; static long userspace_events;
static const char CONSOLE_CLEAR[] = ""; static const char CONSOLE_CLEAR[] = "";
...@@ -634,6 +637,7 @@ static void print_sym_table(void) ...@@ -634,6 +637,7 @@ static void print_sym_table(void)
float events_per_sec = events/delay_secs; float events_per_sec = events/delay_secs;
float kevents_per_sec = (events-userspace_events)/delay_secs; float kevents_per_sec = (events-userspace_events)/delay_secs;
events = userspace_events = 0;
memcpy(tmp, sym_table, sizeof(sym_table[0])*sym_table_count); memcpy(tmp, sym_table, sizeof(sym_table[0])*sym_table_count);
qsort(tmp, sym_table_count, sizeof(tmp[0]), compare); qsort(tmp, sym_table_count, sizeof(tmp[0]), compare);
...@@ -714,8 +718,6 @@ static void print_sym_table(void) ...@@ -714,8 +718,6 @@ static void print_sym_table(void)
if (sym_filter_entry) if (sym_filter_entry)
show_details(sym_filter_entry); show_details(sym_filter_entry);
last_refresh = time(NULL);
{ {
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
...@@ -726,6 +728,16 @@ static void print_sym_table(void) ...@@ -726,6 +728,16 @@ static void print_sym_table(void)
} }
} }
static void *display_thread(void *arg)
{
printf("KernelTop refresh period: %d seconds\n", delay_secs);
while (!sleep(delay_secs))
print_sym_table();
return NULL;
}
static int read_symbol(FILE *in, struct sym_entry *s) static int read_symbol(FILE *in, struct sym_entry *s)
{ {
static int filter_match = 0; static int filter_match = 0;
...@@ -1081,19 +1093,20 @@ static void process_options(int argc, char *argv[]) ...@@ -1081,19 +1093,20 @@ static void process_options(int argc, char *argv[])
{"filter", required_argument, NULL, 'f'}, {"filter", required_argument, NULL, 'f'},
{"group", required_argument, NULL, 'g'}, {"group", required_argument, NULL, 'g'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"scale", no_argument, NULL, 'l'},
{"nmi", required_argument, NULL, 'n'}, {"nmi", required_argument, NULL, 'n'},
{"mmap_info", no_argument, NULL, 'M'},
{"mmap_pages", required_argument, NULL, 'm'},
{"munmap_info", no_argument, NULL, 'U'},
{"pid", required_argument, NULL, 'p'}, {"pid", required_argument, NULL, 'p'},
{"vmlinux", required_argument, NULL, 'x'}, {"realtime", required_argument, NULL, 'r'},
{"scale", no_argument, NULL, 'l'},
{"symbol", required_argument, NULL, 's'}, {"symbol", required_argument, NULL, 's'},
{"stat", no_argument, NULL, 'S'}, {"stat", no_argument, NULL, 'S'},
{"vmlinux", required_argument, NULL, 'x'},
{"zero", no_argument, NULL, 'z'}, {"zero", no_argument, NULL, 'z'},
{"mmap_pages", required_argument, NULL, 'm'},
{"mmap_info", no_argument, NULL, 'M'},
{"munmap_info", no_argument, NULL, 'U'},
{NULL, 0, NULL, 0 } {NULL, 0, NULL, 0 }
}; };
int c = getopt_long(argc, argv, "+:ac:C:d:De:f:g:hln:m:p:s:Sx:zMU", int c = getopt_long(argc, argv, "+:ac:C:d:De:f:g:hln:m:p:r:s:Sx:zMU",
long_options, &option_index); long_options, &option_index);
if (c == -1) if (c == -1)
break; break;
...@@ -1127,6 +1140,7 @@ static void process_options(int argc, char *argv[]) ...@@ -1127,6 +1140,7 @@ static void process_options(int argc, char *argv[])
profile_cpu = -1; profile_cpu = -1;
} }
tid = atoi(optarg); break; tid = atoi(optarg); break;
case 'r': realtime_prio = atoi(optarg); break;
case 's': sym_filter = strdup(optarg); break; case 's': sym_filter = strdup(optarg); break;
case 'S': run_perfstat = 1; break; case 'S': run_perfstat = 1; break;
case 'x': vmlinux = strdup(optarg); break; case 'x': vmlinux = strdup(optarg); break;
...@@ -1289,6 +1303,7 @@ int main(int argc, char *argv[]) ...@@ -1289,6 +1303,7 @@ int main(int argc, char *argv[])
struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
struct perf_counter_hw_event hw_event; struct perf_counter_hw_event hw_event;
pthread_t thread;
int i, counter, group_fd, nr_poll = 0; int i, counter, group_fd, nr_poll = 0;
unsigned int cpu; unsigned int cpu;
int ret; int ret;
...@@ -1363,8 +1378,20 @@ int main(int argc, char *argv[]) ...@@ -1363,8 +1378,20 @@ int main(int argc, char *argv[])
} }
} }
printf("KernelTop refresh period: %d seconds\n", delay_secs); if (pthread_create(&thread, NULL, display_thread, NULL)) {
last_refresh = time(NULL); printf("Could not create display thread.\n");
exit(-1);
}
if (realtime_prio) {
struct sched_param param;
param.sched_priority = realtime_prio;
if (sched_setscheduler(0, SCHED_FIFO, &param)) {
printf("Could not set realtime priority.\n");
exit(-1);
}
}
while (1) { while (1) {
int hits = events; int hits = events;
...@@ -1374,14 +1401,8 @@ int main(int argc, char *argv[]) ...@@ -1374,14 +1401,8 @@ int main(int argc, char *argv[])
mmap_read(&mmap_array[i][counter]); mmap_read(&mmap_array[i][counter]);
} }
if (time(NULL) >= last_refresh + delay_secs) {
print_sym_table();
events = userspace_events = 0;
}
if (hits == events) if (hits == events)
ret = poll(event_array, nr_poll, 1000); ret = poll(event_array, nr_poll, 100);
hits = events;
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment