Build with:
- cc -O6 -Wall -lrt `pkg-config --cflags --libs glib-2.0` -o kerneltop kerneltop.c
+ cc -O6 -Wall -c -o kerneltop.o kerneltop.c -lrt
Sample output:
* Yanmin Zhang <yanmin.zhang@intel.com>
* Wu Fengguang <fengguang.wu@intel.com>
* Mike Galbraith <efault@gmx.de>
+ * Paul Mackerras <paulus@samba.org>
*
* Released under the GPL v2. (and only v2, not any later version)
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <getopt.h>
#include <assert.h>
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
-#include <glib.h>
-
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/mman.h>
#include <linux/unistd.h>
+#include <linux/types.h>
#include "../../include/linux/perf_counter.h"
#define __user
#define asmlinkage
-typedef unsigned int __u32;
-typedef unsigned long long __u64;
-typedef long long __s64;
-
-
#ifdef __x86_64__
#define __NR_perf_counter_open 295
#define rmb() asm volatile("lfence" ::: "memory")
int group_fd,
unsigned long flags)
{
- int ret;
-
- ret = syscall(
+ return syscall(
__NR_perf_counter_open, hw_event_uptr, pid, cpu, group_fd, flags);
-#if defined(__x86_64__) || defined(__i386__)
- if (ret < 0 && ret > -4096) {
- errno = -ret;
- ret = -1;
- }
-#endif
- return ret;
}
#define MAX_COUNTERS 64
static int nr_counters = 0;
static __u64 event_id[MAX_COUNTERS] = {
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
- EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
+ EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),
static int zero;
static int dump_symtab;
-static GList *lines;
-
struct source_line {
uint64_t EIP;
unsigned long count;
char *line;
+ struct source_line *next;
};
+static struct source_line *lines;
+static struct source_line **lines_tail;
const unsigned int default_count[] = {
1000000,
count += single_count;
}
- if (!PERF_COUNTER_RAW(event_id[counter]) &&
- (event_id[counter] == PERF_COUNT_CPU_CLOCK ||
- event_id[counter] == PERF_COUNT_TASK_CLOCK)) {
+ if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK) ||
+ event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK)) {
double msecs = (double)count / 1000000;
fprintf(stderr, " %14Ld %-20s (events)\n",
count, event_name(counter));
}
- if (!counter)
- fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
fprintf(stderr, " Wall-clock time elapsed: %12.6f msecs\n",
char *sym;
unsigned long count[MAX_COUNTERS];
int skip;
- GList *source;
+ struct source_line *source;
};
#define MAX_SYMS 100000
if (!file)
return;
+ lines_tail = &lines;
while (!feof(file)) {
struct source_line *src;
size_t dummy = 0;
if (c)
*c = 0;
- lines = g_list_prepend(lines, src);
+ src->next = NULL;
+ *lines_tail = src;
+ lines_tail = &src->next;
if (strlen(src->line)>8 && src->line[8] == ':')
src->EIP = strtoull(src->line, NULL, 16);
src->EIP = strtoull(src->line, NULL, 16);
}
pclose(file);
- lines = g_list_reverse(lines);
}
static void record_precise_ip(uint64_t ip)
{
struct source_line *line;
- GList *item;
- item = g_list_first(lines);
- while (item) {
- line = item->data;
+ for (line = lines; line; line = line->next) {
if (line->EIP == ip)
line->count++;
if (line->EIP > ip)
break;
- item = g_list_next(item);
}
}
static void lookup_sym_in_vmlinux(struct sym_entry *sym)
{
struct source_line *line;
- GList *item;
char pattern[PATH_MAX];
sprintf(pattern, "<%s>:", sym->sym);
- item = g_list_first(lines);
- while (item) {
- line = item->data;
+ for (line = lines; line; line = line->next) {
if (strstr(line->line, pattern)) {
- sym->source = item;
+ sym->source = line;
break;
}
- item = g_list_next(item);
}
}
-void show_lines(GList *item_queue, int item_queue_count)
+static void show_lines(struct source_line *line_queue, int line_queue_count)
{
int i;
struct source_line *line;
- for (i = 0; i < item_queue_count; i++) {
- line = item_queue->data;
+ line = line_queue;
+ for (i = 0; i < line_queue_count; i++) {
printf("%8li\t%s\n", line->count, line->line);
- item_queue = g_list_next(item_queue);
+ line = line->next;
}
}
static void show_details(struct sym_entry *sym)
{
struct source_line *line;
- GList *item;
+ struct source_line *line_queue = NULL;
int displayed = 0;
- GList *item_queue = NULL;
- int item_queue_count = 0;
+ int line_queue_count = 0;
if (!sym->source)
lookup_sym_in_vmlinux(sym);
printf("Showing details for %s\n", sym->sym);
- item = sym->source;
- while (item) {
- line = item->data;
+ line = sym->source;
+ while (line) {
if (displayed && strstr(line->line, ">:"))
break;
- if (!item_queue_count)
- item_queue = item;
- item_queue_count ++;
+ if (!line_queue_count)
+ line_queue = line;
+ line_queue_count ++;
if (line->count >= count_filter) {
- show_lines(item_queue, item_queue_count);
- item_queue_count = 0;
- item_queue = NULL;
- } else if (item_queue_count > TRACE_COUNT) {
- item_queue = g_list_next(item_queue);
- item_queue_count --;
+ show_lines(line_queue, line_queue_count);
+ line_queue_count = 0;
+ line_queue = NULL;
+ } else if (line_queue_count > TRACE_COUNT) {
+ line_queue = line_queue->next;
+ line_queue_count --;
}
line->count = 0;
displayed++;
if (displayed > 300)
break;
- item = g_list_next(item);
+ line = line->next;
}
}
if (tid != -1 || profile_cpu != -1)
nr_cpus = 1;
+ parse_symbols();
+ if (vmlinux && sym_filter_entry)
+ parse_vmlinux(vmlinux);
+
for (i = 0; i < nr_cpus; i++) {
group_fd = -1;
for (counter = 0; counter < nr_counters; counter++) {
hw_event.nmi = nmi;
fd[i][counter] = sys_perf_counter_open(&hw_event, tid, cpu, group_fd, 0);
- fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
if (fd[i][counter] < 0) {
+ int err = errno;
printf("kerneltop error: syscall returned with %d (%s)\n",
- fd[i][counter], strerror(-fd[i][counter]));
- if (fd[i][counter] == -1)
+ fd[i][counter], strerror(err));
+ if (err == EPERM)
printf("Are you root?\n");
exit(-1);
}
assert(fd[i][counter] >= 0);
+ fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
/*
* First counter acts as the group leader:
}
}
- parse_symbols();
- if (vmlinux && sym_filter_entry)
- parse_vmlinux(vmlinux);
-
printf("KernelTop refresh period: %d seconds\n", delay_secs);
last_refresh = time(NULL);