2 * kerneltop.c: show top kernel functions - performance counters showcase
6 cc -O6 -Wall -lrt `pkg-config --cflags --libs glib-2.0` -o kerneltop kerneltop.c
10 ------------------------------------------------------------------------------
11 KernelTop: 2669 irqs/sec [NMI, cache-misses/cache-refs], (all, cpu: 2)
12 ------------------------------------------------------------------------------
14 weight RIP kernel function
15 ______ ________________ _______________
17 35.20 - ffffffff804ce74b : skb_copy_and_csum_dev
18 33.00 - ffffffff804cb740 : sock_alloc_send_skb
19 31.26 - ffffffff804ce808 : skb_push
20 22.43 - ffffffff80510004 : tcp_established_options
21 19.00 - ffffffff8027d250 : find_get_page
22 15.76 - ffffffff804e4fc9 : eth_type_trans
23 15.20 - ffffffff804d8baa : dst_release
24 14.86 - ffffffff804cf5d8 : skb_release_head_state
25 14.00 - ffffffff802217d5 : read_hpet
26 12.00 - ffffffff804ffb7f : __ip_local_out
27 11.97 - ffffffff804fc0c8 : ip_local_deliver_finish
28 8.54 - ffffffff805001a3 : ip_queue_xmit
32 * perfstat: /usr/bin/time -alike performance counter statistics utility
34 It summarizes the counter events of all tasks (and child tasks),
35 covering all CPUs that the command (or workload) executes on.
36 It only counts the per-task events of the workload started,
37 independent of how many other tasks run on those CPUs.
41 $ ./perfstat -e 1 -e 3 -e 5 ls -lR /usr/include/ >/dev/null
43 Performance counter stats for 'ls':
45 163516953 instructions
51 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
53 * Improvements and fixes by:
55 * Arjan van de Ven <arjan@linux.intel.com>
56 * Yanmin Zhang <yanmin.zhang@intel.com>
57 * Wu Fengguang <fengguang.wu@intel.com>
58 * Mike Galbraith <efault@gmx.de>
60 * Released under the GPL v2. (and only v2, not any later version)
64 #include <sys/types.h>
81 #include <sys/syscall.h>
82 #include <sys/ioctl.h>
84 #include <sys/prctl.h>
88 #include <linux/unistd.h>
90 #include "perfcounters.h"
93 #define MAX_COUNTERS 64
94 #define MAX_NR_CPUS 256
96 #define DEF_PERFSTAT_EVENTS { -2, -5, -4, -3, 0, 1, 2, 3}
98 static int run_perfstat
= 0;
99 static int system_wide
= 0;
101 static int nr_counters
= 0;
102 static __s64 event_id
[MAX_COUNTERS
] = DEF_PERFSTAT_EVENTS
;
103 static int event_raw
[MAX_COUNTERS
];
104 static int event_count
[MAX_COUNTERS
];
105 static int fd
[MAX_NR_CPUS
][MAX_COUNTERS
];
107 static __u64 count_filter
= 100;
110 static int profile_cpu
= -1;
111 static int nr_cpus
= 0;
113 static int group
= 0;
115 static char *vmlinux
;
117 static char *sym_filter
;
118 static unsigned long filter_start
;
119 static unsigned long filter_end
;
121 static int delay_secs
= 2;
123 static int dump_symtab
;
134 const unsigned int default_count
[] = {
143 static char *hw_event_names
[] = {
153 static char *sw_event_names
[] = {
161 struct event_symbol
{
166 static struct event_symbol event_symbols
[] = {
167 {PERF_COUNT_CPU_CYCLES
, "cpu-cycles", },
168 {PERF_COUNT_CPU_CYCLES
, "cycles", },
169 {PERF_COUNT_INSTRUCTIONS
, "instructions", },
170 {PERF_COUNT_CACHE_REFERENCES
, "cache-references", },
171 {PERF_COUNT_CACHE_MISSES
, "cache-misses", },
172 {PERF_COUNT_BRANCH_INSTRUCTIONS
, "branch-instructions", },
173 {PERF_COUNT_BRANCH_INSTRUCTIONS
, "branches", },
174 {PERF_COUNT_BRANCH_MISSES
, "branch-misses", },
175 {PERF_COUNT_BUS_CYCLES
, "bus-cycles", },
176 {PERF_COUNT_CPU_CLOCK
, "cpu-ticks", },
177 {PERF_COUNT_CPU_CLOCK
, "ticks", },
178 {PERF_COUNT_TASK_CLOCK
, "task-ticks", },
179 {PERF_COUNT_PAGE_FAULTS
, "page-faults", },
180 {PERF_COUNT_PAGE_FAULTS
, "faults", },
181 {PERF_COUNT_CONTEXT_SWITCHES
, "context-switches", },
182 {PERF_COUNT_CONTEXT_SWITCHES
, "cs", },
183 {PERF_COUNT_CPU_MIGRATIONS
, "cpu-migrations", },
184 {PERF_COUNT_CPU_MIGRATIONS
, "migrations", },
187 static void display_events_help(void)
193 " -e EVENT --event=EVENT # symbolic-name abbreviations");
195 for (i
= 0, e
= PERF_HW_EVENTS_MAX
; i
< ARRAY_SIZE(event_symbols
); i
++) {
196 if (e
!= event_symbols
[i
].event
) {
197 e
= event_symbols
[i
].event
;
199 "\n %2d: %-20s", e
, event_symbols
[i
].symbol
);
201 printf(" %s", event_symbols
[i
].symbol
);
205 " rNNN: raw PMU events (eventsel+umask)\n\n");
208 static void display_perfstat_help(void)
211 "Usage: perfstat [<events...>] <cmd...>\n\n"
212 "PerfStat Options (up to %d event types can be specified):\n\n",
215 display_events_help();
218 " -a # system-wide collection\n");
222 static void display_help(void)
225 return display_perfstat_help();
228 "Usage: kerneltop [<options>]\n"
229 " Or: kerneltop -S [<options>] COMMAND [ARGS]\n\n"
230 "KernelTop Options (up to %d event types can be specified at once):\n\n",
233 display_events_help();
236 " -S --stat # perfstat COMMAND\n"
237 " -a # system-wide collection (for perfstat)\n\n"
238 " -c CNT --count=CNT # event period to sample\n\n"
239 " -C CPU --cpu=CPU # CPU (-1 for all) [default: -1]\n"
240 " -p PID --pid=PID # PID of sampled task (-1 for all) [default: -1]\n\n"
241 " -d delay --delay=<seconds> # sampling/display delay [default: 2]\n"
242 " -f CNT --filter=CNT # min-event-count filter [default: 100]\n\n"
243 " -s symbol --symbol=<symbol> # function to be showed annotated one-shot\n"
244 " -x path --vmlinux=<path> # the vmlinux binary, required for -s use\n"
245 " -z --zero # zero counts after display\n"
246 " -D --dump_symtab # dump symbol table to stderr on startup\n"
252 static int type_valid(int type
)
254 if (type
>= PERF_HW_EVENTS_MAX
)
256 if (type
<= PERF_SW_EVENTS_MIN
)
262 static char *event_name(int ctr
)
264 __s64 type
= event_id
[ctr
];
267 if (event_raw
[ctr
]) {
268 sprintf(buf
, "raw 0x%llx", (long long)type
);
271 if (!type_valid(type
))
275 return hw_event_names
[type
];
277 return sw_event_names
[-type
-1];
281 * Each event can have multiple symbolic names.
282 * Symbolic names are (almost) exactly matched.
284 static int match_event_symbols(char *str
)
288 if (isdigit(str
[0]) || str
[0] == '-')
291 for (i
= 0; i
< ARRAY_SIZE(event_symbols
); i
++) {
292 if (!strncmp(str
, event_symbols
[i
].symbol
,
293 strlen(event_symbols
[i
].symbol
)))
294 return event_symbols
[i
].event
;
297 return PERF_HW_EVENTS_MAX
;
300 static int parse_events(char *str
)
306 if (nr_counters
== MAX_COUNTERS
)
313 type
= strtol(str
, NULL
, 16);
315 type
= match_event_symbols(str
);
316 if (!type_valid(type
))
320 event_id
[nr_counters
] = type
;
321 event_raw
[nr_counters
] = raw
;
324 str
= strstr(str
, ",");
338 char fault_here
[1000000];
340 static void create_perfstat_counter(int counter
)
342 struct perf_counter_hw_event hw_event
;
344 memset(&hw_event
, 0, sizeof(hw_event
));
345 hw_event
.type
= event_id
[counter
];
346 hw_event
.raw
= event_raw
[counter
];
347 hw_event
.record_type
= PERF_RECORD_SIMPLE
;
352 for (cpu
= 0; cpu
< nr_cpus
; cpu
++) {
353 fd
[cpu
][counter
] = sys_perf_counter_open(&hw_event
, -1, cpu
, -1, 0);
354 if (fd
[cpu
][counter
] < 0) {
355 printf("perfstat error: syscall returned with %d (%s)\n",
356 fd
[cpu
][counter
], strerror(errno
));
361 hw_event
.inherit
= 1;
362 hw_event
.disabled
= 1;
364 fd
[0][counter
] = sys_perf_counter_open(&hw_event
, 0, -1, -1, 0);
365 if (fd
[0][counter
] < 0) {
366 printf("perfstat error: syscall returned with %d (%s)\n",
367 fd
[0][counter
], strerror(errno
));
373 int do_perfstat(int argc
, char *argv
[])
375 unsigned long long t0
, t1
;
384 for (counter
= 0; counter
< nr_counters
; counter
++)
385 create_perfstat_counter(counter
);
391 * Enable counters and exec the command:
394 prctl(PR_TASK_PERF_COUNTERS_ENABLE
);
396 if ((pid
= fork()) < 0)
397 perror("failed to fork");
399 if (execvp(argv
[0], argv
)) {
404 while (wait(&status
) >= 0)
406 prctl(PR_TASK_PERF_COUNTERS_DISABLE
);
411 fprintf(stderr
, "\n");
412 fprintf(stderr
, " Performance counter stats for \'%s\':\n",
414 fprintf(stderr
, "\n");
416 for (counter
= 0; counter
< nr_counters
; counter
++) {
418 __u64 count
, single_count
;
421 for (cpu
= 0; cpu
< nr_cpus
; cpu
++) {
422 res
= read(fd
[cpu
][counter
],
423 (char *) &single_count
, sizeof(single_count
));
424 assert(res
== sizeof(single_count
));
425 count
+= single_count
;
428 if (!event_raw
[counter
] &&
429 (event_id
[counter
] == PERF_COUNT_CPU_CLOCK
||
430 event_id
[counter
] == PERF_COUNT_TASK_CLOCK
)) {
432 double msecs
= (double)count
/ 1000000;
434 fprintf(stderr
, " %14.6f %-20s (msecs)\n",
435 msecs
, event_name(counter
));
437 fprintf(stderr
, " %14Ld %-20s (events)\n",
438 count
, event_name(counter
));
441 fprintf(stderr
, "\n");
443 fprintf(stderr
, "\n");
444 fprintf(stderr
, " Wall-clock time elapsed: %12.6f msecs\n",
445 (double)(t1
-t0
)/1e6
);
446 fprintf(stderr
, "\n");
455 static uint64_t min_ip
;
456 static uint64_t max_ip
= -1ll;
459 unsigned long long addr
;
461 unsigned long count
[MAX_COUNTERS
];
466 #define MAX_SYMS 100000
468 static int sym_table_count
;
470 struct sym_entry
*sym_filter_entry
;
472 static struct sym_entry sym_table
[MAX_SYMS
];
474 static void show_details(struct sym_entry
*sym
);
477 * Ordering weight: count-1 * count-2 * ... / count-n
479 static double sym_weight(const struct sym_entry
*sym
)
484 weight
= sym
->count
[0];
486 for (counter
= 1; counter
< nr_counters
-1; counter
++)
487 weight
*= sym
->count
[counter
];
489 weight
/= (sym
->count
[counter
] + 1);
494 static int compare(const void *__sym1
, const void *__sym2
)
496 const struct sym_entry
*sym1
= __sym1
, *sym2
= __sym2
;
498 return sym_weight(sym1
) < sym_weight(sym2
);
501 static time_t last_refresh
;
503 static long userspace_events
;
504 static const char CONSOLE_CLEAR
[] = "\e[H\e[2J";
506 static struct sym_entry tmp
[MAX_SYMS
];
508 static void print_sym_table(void)
512 float events_per_sec
= events
/delay_secs
;
513 float kevents_per_sec
= (events
-userspace_events
)/delay_secs
;
515 memcpy(tmp
, sym_table
, sizeof(sym_table
[0])*sym_table_count
);
516 qsort(tmp
, sym_table_count
, sizeof(tmp
[0]), compare
);
518 write(1, CONSOLE_CLEAR
, strlen(CONSOLE_CLEAR
));
521 "------------------------------------------------------------------------------\n");
522 printf( " KernelTop:%8.0f irqs/sec kernel:%3.1f%% [%s, ",
524 100.0 - (100.0*((events_per_sec
-kevents_per_sec
)/events_per_sec
)),
525 nmi
? "NMI" : "IRQ");
527 if (nr_counters
== 1)
528 printf("%d ", event_count
[0]);
530 for (counter
= 0; counter
< nr_counters
; counter
++) {
534 printf("%s", event_name(counter
));
540 printf(" (tid: %d", tid
);
544 if (profile_cpu
!= -1)
545 printf(", cpu: %d)\n", profile_cpu
);
550 printf(", %d CPUs)\n", nr_cpus
);
553 printf("------------------------------------------------------------------------------\n\n");
555 if (nr_counters
== 1)
558 printf(" weight events");
560 printf(" RIP kernel function\n"
561 " ______ ______ ________________ _______________\n\n"
565 for (i
= 0; i
< sym_table_count
; i
++) {
568 if (nr_counters
== 1) {
570 tmp
[i
].count
[0] >= count_filter
) {
571 printf("%19.2f - %016llx : %s\n",
572 sym_weight(tmp
+ i
), tmp
[i
].addr
, tmp
[i
].sym
);
577 tmp
[i
].count
[0] >= count_filter
) {
578 printf("%8.1f %10ld - %016llx : %s\n",
581 tmp
[i
].addr
, tmp
[i
].sym
);
586 * Add decay to the counts:
588 for (count
= 0; count
< nr_counters
; count
++)
589 sym_table
[i
].count
[count
] = zero
? 0 : sym_table
[i
].count
[count
] * 7 / 8;
592 if (sym_filter_entry
)
593 show_details(sym_filter_entry
);
595 last_refresh
= time(NULL
);
598 struct pollfd stdin_poll
= { .fd
= 0, .events
= POLLIN
};
600 if (poll(&stdin_poll
, 1, 0) == 1) {
601 printf("key pressed - exiting.\n");
607 static int read_symbol(FILE *in
, struct sym_entry
*s
)
609 static int filter_match
= 0;
614 rc
= fscanf(in
, "%llx %c %499s", &s
->addr
, &stype
, str
);
620 /* skip until end of line: */
624 if (rc
== '\n' || rc
== EOF
|| pos
>= 499)
633 /* Filter out known duplicates and non-text symbols. */
634 if (!strcmp(sym
, "_text"))
636 if (!min_ip
&& !strcmp(sym
, "_stext"))
638 if (!strcmp(sym
, "_etext") || !strcmp(sym
, "_sinittext"))
640 if (stype
!= 'T' && stype
!= 't')
642 if (!strncmp("init_module", sym
, 11) || !strncmp("cleanup_module", sym
, 14))
644 if (strstr(sym
, "_text_start") || strstr(sym
, "_text_end"))
647 s
->sym
= malloc(strlen(str
));
650 strcpy((char *)s
->sym
, str
);
653 /* Tag events to be skipped. */
654 if (!strcmp("default_idle", s
->sym
) || !strcmp("cpu_idle", s
->sym
))
656 if (!strcmp("enter_idle", s
->sym
) || !strcmp("exit_idle", s
->sym
))
659 if (filter_match
== 1) {
660 filter_end
= s
->addr
;
662 if (filter_end
- filter_start
> 10000) {
663 printf("hm, too large filter symbol <%s> - skipping.\n",
665 printf("symbol filter start: %016lx\n", filter_start
);
666 printf(" end: %016lx\n", filter_end
);
667 filter_end
= filter_start
= 0;
672 if (filter_match
== 0 && sym_filter
&& !strcmp(s
->sym
, sym_filter
)) {
674 filter_start
= s
->addr
;
680 int compare_addr(const void *__sym1
, const void *__sym2
)
682 const struct sym_entry
*sym1
= __sym1
, *sym2
= __sym2
;
684 return sym1
->addr
> sym2
->addr
;
687 static void sort_symbol_table(void)
692 qsort(sym_table
, sym_table_count
, sizeof(sym_table
[0]), compare_addr
);
693 for (i
= 0, dups
= 0; i
< sym_table_count
; i
++) {
694 if (sym_table
[i
].addr
== sym_table
[i
+1].addr
) {
695 sym_table
[i
+1].addr
= -1ll;
699 sym_table_count
-= dups
;
703 static void parse_symbols(void)
705 struct sym_entry
*last
;
707 FILE *kallsyms
= fopen("/proc/kallsyms", "r");
710 printf("Could not open /proc/kallsyms - no CONFIG_KALLSYMS_ALL=y?\n");
714 while (!feof(kallsyms
)) {
715 if (read_symbol(kallsyms
, &sym_table
[sym_table_count
]) == 0) {
717 assert(sym_table_count
<= MAX_SYMS
);
722 min_ip
= sym_table
[0].addr
;
723 max_ip
= sym_table
[sym_table_count
-1].addr
;
724 last
= sym_table
+ sym_table_count
++;
731 for (count
=0; count
< sym_table_count
; count
++) {
732 if (!strcmp(sym_table
[count
].sym
, sym_filter
)) {
733 sym_filter_entry
= &sym_table
[count
];
741 for (i
= 0; i
< sym_table_count
; i
++)
742 fprintf(stderr
, "%llx %s\n",
743 sym_table
[i
].addr
, sym_table
[i
].sym
);
751 static void parse_vmlinux(char *filename
)
754 char command
[PATH_MAX
*2];
758 sprintf(command
, "objdump --start-address=0x%016lx --stop-address=0x%016lx -dS %s", filter_start
, filter_end
, filename
);
760 file
= popen(command
, "r");
764 while (!feof(file
)) {
765 struct source_line
*src
;
769 src
= malloc(sizeof(struct source_line
));
771 memset(src
, 0, sizeof(struct source_line
));
773 if (getline(&src
->line
, &dummy
, file
) < 0)
778 c
= strchr(src
->line
, '\n');
782 lines
= g_list_prepend(lines
, src
);
784 if (strlen(src
->line
)>8 && src
->line
[8] == ':')
785 src
->EIP
= strtoull(src
->line
, NULL
, 16);
786 if (strlen(src
->line
)>8 && src
->line
[16] == ':')
787 src
->EIP
= strtoull(src
->line
, NULL
, 16);
790 lines
= g_list_reverse(lines
);
793 static void record_precise_ip(uint64_t ip
)
795 struct source_line
*line
;
798 item
= g_list_first(lines
);
805 item
= g_list_next(item
);
809 static void lookup_sym_in_vmlinux(struct sym_entry
*sym
)
811 struct source_line
*line
;
813 char pattern
[PATH_MAX
];
814 sprintf(pattern
, "<%s>:", sym
->sym
);
816 item
= g_list_first(lines
);
819 if (strstr(line
->line
, pattern
)) {
823 item
= g_list_next(item
);
827 void show_lines(GList
*item_queue
, int item_queue_count
)
830 struct source_line
*line
;
832 for (i
= 0; i
< item_queue_count
; i
++) {
833 line
= item_queue
->data
;
834 printf("%8li\t%s\n", line
->count
, line
->line
);
835 item_queue
= g_list_next(item_queue
);
839 #define TRACE_COUNT 3
841 static void show_details(struct sym_entry
*sym
)
843 struct source_line
*line
;
846 GList
*item_queue
= NULL
;
847 int item_queue_count
= 0;
850 lookup_sym_in_vmlinux(sym
);
854 printf("Showing details for %s\n", sym
->sym
);
859 if (displayed
&& strstr(line
->line
, ">:"))
862 if (!item_queue_count
)
866 if (line
->count
>= count_filter
) {
867 show_lines(item_queue
, item_queue_count
);
868 item_queue_count
= 0;
870 } else if (item_queue_count
> TRACE_COUNT
) {
871 item_queue
= g_list_next(item_queue
);
879 item
= g_list_next(item
);
884 * Binary search in the histogram table and record the hit:
886 static void record_ip(uint64_t ip
, int counter
)
888 int left_idx
, middle_idx
, right_idx
, idx
;
889 unsigned long left
, middle
, right
;
891 record_precise_ip(ip
);
894 right_idx
= sym_table_count
-1;
895 assert(ip
<= max_ip
&& ip
>= min_ip
);
897 while (left_idx
+ 1 < right_idx
) {
898 middle_idx
= (left_idx
+ right_idx
) / 2;
900 left
= sym_table
[ left_idx
].addr
;
901 middle
= sym_table
[middle_idx
].addr
;
902 right
= sym_table
[ right_idx
].addr
;
904 if (!(left
<= middle
&& middle
<= right
)) {
905 printf("%016lx...\n%016lx...\n%016lx\n", left
, middle
, right
);
906 printf("%d %d %d\n", left_idx
, middle_idx
, right_idx
);
908 assert(left
<= middle
&& middle
<= right
);
909 if (!(left
<= ip
&& ip
<= right
)) {
910 printf(" left: %016lx\n", left
);
911 printf(" ip: %016lx\n", ip
);
912 printf("right: %016lx\n", right
);
914 assert(left
<= ip
&& ip
<= right
);
916 * [ left .... target .... middle .... right ]
920 right_idx
= middle_idx
;
924 * [ left .... middle ... target ... right ]
927 left_idx
= middle_idx
;
932 if (!sym_table
[idx
].skip
)
933 sym_table
[idx
].count
[counter
]++;
937 static void process_event(uint64_t ip
, int counter
)
941 if (ip
< min_ip
|| ip
> max_ip
) {
946 record_ip(ip
, counter
);
949 static void process_options(int argc
, char *argv
[])
951 int error
= 0, counter
;
953 if (strstr(argv
[0], "perfstat"))
957 int option_index
= 0;
958 /** Options for getopt */
959 static struct option long_options
[] = {
960 {"count", required_argument
, NULL
, 'c'},
961 {"cpu", required_argument
, NULL
, 'C'},
962 {"delay", required_argument
, NULL
, 'd'},
963 {"dump_symtab", no_argument
, NULL
, 'D'},
964 {"event", required_argument
, NULL
, 'e'},
965 {"filter", required_argument
, NULL
, 'f'},
966 {"group", required_argument
, NULL
, 'g'},
967 {"help", no_argument
, NULL
, 'h'},
968 {"nmi", required_argument
, NULL
, 'n'},
969 {"pid", required_argument
, NULL
, 'p'},
970 {"vmlinux", required_argument
, NULL
, 'x'},
971 {"symbol", required_argument
, NULL
, 's'},
972 {"stat", no_argument
, NULL
, 'S'},
973 {"zero", no_argument
, NULL
, 'z'},
976 int c
= getopt_long(argc
, argv
, "+:ac:C:d:De:f:g:hn:p:s:Sx:z",
977 long_options
, &option_index
);
982 case 'a': system_wide
= 1; break;
983 case 'c': event_count
[nr_counters
] = atoi(optarg
); break;
985 /* CPU and PID are mutually exclusive */
987 printf("WARNING: CPU switch overriding PID\n");
991 profile_cpu
= atoi(optarg
); break;
992 case 'd': delay_secs
= atoi(optarg
); break;
993 case 'D': dump_symtab
= 1; break;
995 case 'e': error
= parse_events(optarg
); break;
997 case 'f': count_filter
= atoi(optarg
); break;
998 case 'g': group
= atoi(optarg
); break;
999 case 'h': display_help(); break;
1000 case 'n': nmi
= atoi(optarg
); break;
1002 /* CPU and PID are mutually exclusive */
1003 if (profile_cpu
!= -1) {
1004 printf("WARNING: PID switch overriding CPU\n");
1008 tid
= atoi(optarg
); break;
1009 case 's': sym_filter
= strdup(optarg
); break;
1010 case 'S': run_perfstat
= 1; break;
1011 case 'x': vmlinux
= strdup(optarg
); break;
1012 case 'z': zero
= 1; break;
1013 default: error
= 1; break;
1028 for (counter
= 0; counter
< nr_counters
; counter
++) {
1029 if (event_count
[counter
])
1032 if (event_id
[counter
] < PERF_HW_EVENTS_MAX
)
1033 event_count
[counter
] = default_count
[event_id
[counter
]];
1035 event_count
[counter
] = 100000;
1039 int main(int argc
, char *argv
[])
1041 struct pollfd event_array
[MAX_NR_CPUS
][MAX_COUNTERS
];
1042 struct perf_counter_hw_event hw_event
;
1043 int i
, counter
, group_fd
;
1049 process_options(argc
, argv
);
1051 nr_cpus
= sysconf(_SC_NPROCESSORS_ONLN
);
1052 assert(nr_cpus
<= MAX_NR_CPUS
);
1053 assert(nr_cpus
>= 0);
1056 return do_perfstat(argc
, argv
);
1058 if (tid
!= -1 || profile_cpu
!= -1)
1061 for (i
= 0; i
< nr_cpus
; i
++) {
1063 for (counter
= 0; counter
< nr_counters
; counter
++) {
1066 if (tid
== -1 && profile_cpu
== -1)
1069 memset(&hw_event
, 0, sizeof(hw_event
));
1070 hw_event
.type
= event_id
[counter
];
1071 hw_event
.raw
= event_raw
[counter
];
1072 hw_event
.irq_period
= event_count
[counter
];
1073 hw_event
.record_type
= PERF_RECORD_IRQ
;
1076 fd
[i
][counter
] = sys_perf_counter_open(&hw_event
, tid
, cpu
, group_fd
, 0);
1077 fcntl(fd
[i
][counter
], F_SETFL
, O_NONBLOCK
);
1078 if (fd
[i
][counter
] < 0) {
1079 printf("kerneltop error: syscall returned with %d (%s)\n",
1080 fd
[i
][counter
], strerror(-fd
[i
][counter
]));
1081 if (fd
[i
][counter
] == -1)
1082 printf("Are you root?\n");
1085 assert(fd
[i
][counter
] >= 0);
1088 * First counter acts as the group leader:
1090 if (group
&& group_fd
== -1)
1091 group_fd
= fd
[i
][counter
];
1093 event_array
[i
][counter
].fd
= fd
[i
][counter
];
1094 event_array
[i
][counter
].events
= POLLIN
;
1099 if (vmlinux
&& sym_filter_entry
)
1100 parse_vmlinux(vmlinux
);
1102 printf("KernelTop refresh period: %d seconds\n", delay_secs
);
1103 last_refresh
= time(NULL
);
1108 for (i
= 0; i
< nr_cpus
; i
++) {
1109 for (counter
= 0; counter
< nr_counters
; counter
++) {
1110 res
= read(fd
[i
][counter
], (char *) &ip
, sizeof(ip
));
1112 assert(res
== sizeof(ip
));
1114 process_event(ip
, counter
);
1119 if (time(NULL
) >= last_refresh
+ delay_secs
) {
1121 events
= userspace_events
= 0;
1125 ret
= poll(event_array
[0], nr_cpus
, 1000);