Commit 803d4f39 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

perf_counter tools: update to new syscall ABI

update the kerneltop userspace to work with the latest syscall ABI
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Paul Mackerras <paulus@samba.org>
Orig-LKML-Reference: <20090323172417.559643732@chello.nl>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 7b732a75
...@@ -87,20 +87,90 @@ ...@@ -87,20 +87,90 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include "perfcounters.h" #include "include/linux/perf_counter.h"
/*
* prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
* counters in the current task.
*/
#define PR_TASK_PERF_COUNTERS_DISABLE 31
#define PR_TASK_PERF_COUNTERS_ENABLE 32
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define rdclock() \
({ \
struct timespec ts; \
\
clock_gettime(CLOCK_MONOTONIC, &ts); \
ts.tv_sec * 1000000000ULL + ts.tv_nsec; \
})
/*
* Pick up some kernel type conventions:
*/
#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
#endif
#ifdef __i386__
# define __NR_perf_counter_open 333
#endif
#ifdef __powerpc__
#define __NR_perf_counter_open 319
#endif
asmlinkage int sys_perf_counter_open(
struct perf_counter_hw_event *hw_event_uptr __user,
pid_t pid,
int cpu,
int group_fd,
unsigned long flags)
{
int ret;
ret = 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 #define MAX_COUNTERS 64
#define MAX_NR_CPUS 256 #define MAX_NR_CPUS 256
#define DEF_PERFSTAT_EVENTS { -2, -5, -4, -3, 0, 1, 2, 3} #define EID(type, id) (((__u64)(type) << PERF_COUNTER_TYPE_SHIFT) | (id))
static int run_perfstat = 0; static int run_perfstat = 0;
static int system_wide = 0; static int system_wide = 0;
static int nr_counters = 0; static int nr_counters = 0;
static __s64 event_id[MAX_COUNTERS] = DEF_PERFSTAT_EVENTS; static __u64 event_id[MAX_COUNTERS] = {
static int event_raw[MAX_COUNTERS]; EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),
EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS),
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),
};
static int default_interval = 100000;
static int event_count[MAX_COUNTERS]; static int event_count[MAX_COUNTERS];
static int fd[MAX_NR_CPUS][MAX_COUNTERS]; static int fd[MAX_NR_CPUS][MAX_COUNTERS];
...@@ -156,49 +226,63 @@ static char *sw_event_names[] = { ...@@ -156,49 +226,63 @@ static char *sw_event_names[] = {
"pagefaults", "pagefaults",
"context switches", "context switches",
"CPU migrations", "CPU migrations",
"minor faults",
"major faults",
}; };
struct event_symbol { struct event_symbol {
int event; __u64 event;
char *symbol; char *symbol;
}; };
static struct event_symbol event_symbols[] = { static struct event_symbol event_symbols[] = {
{PERF_COUNT_CPU_CYCLES, "cpu-cycles", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
{PERF_COUNT_CPU_CYCLES, "cycles", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
{PERF_COUNT_INSTRUCTIONS, "instructions", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
{PERF_COUNT_CACHE_REFERENCES, "cache-references", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
{PERF_COUNT_CACHE_MISSES, "cache-misses", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
{PERF_COUNT_BRANCH_INSTRUCTIONS, "branch-instructions", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
{PERF_COUNT_BRANCH_INSTRUCTIONS, "branches", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
{PERF_COUNT_BRANCH_MISSES, "branch-misses", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
{PERF_COUNT_BUS_CYCLES, "bus-cycles", }, {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
{PERF_COUNT_CPU_CLOCK, "cpu-ticks", },
{PERF_COUNT_CPU_CLOCK, "ticks", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
{PERF_COUNT_TASK_CLOCK, "task-ticks", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
{PERF_COUNT_PAGE_FAULTS, "page-faults", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
{PERF_COUNT_PAGE_FAULTS, "faults", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
{PERF_COUNT_CONTEXT_SWITCHES, "context-switches", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
{PERF_COUNT_CONTEXT_SWITCHES, "cs", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
{PERF_COUNT_CPU_MIGRATIONS, "cpu-migrations", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
{PERF_COUNT_CPU_MIGRATIONS, "migrations", }, {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
}; };
#define __PERF_COUNTER_FIELD(config, name) \
((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
static void display_events_help(void) static void display_events_help(void)
{ {
unsigned int i; unsigned int i;
int e; __u64 e;
printf( printf(
" -e EVENT --event=EVENT # symbolic-name abbreviations"); " -e EVENT --event=EVENT # symbolic-name abbreviations");
for (i = 0, e = PERF_HW_EVENTS_MAX; i < ARRAY_SIZE(event_symbols); i++) { for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
if (e != event_symbols[i].event) { int type, id;
e = event_symbols[i].event; e = event_symbols[i].event;
printf( type = PERF_COUNTER_TYPE(e);
"\n %2d: %-20s", e, event_symbols[i].symbol); id = PERF_COUNTER_ID(e);
} else
printf(" %s", event_symbols[i].symbol); printf("\n %d:%d: %-20s",
type, id, event_symbols[i].symbol);
} }
printf("\n" printf("\n"
...@@ -249,44 +333,51 @@ static void display_help(void) ...@@ -249,44 +333,51 @@ static void display_help(void)
exit(0); exit(0);
} }
static int type_valid(int type)
{
if (type >= PERF_HW_EVENTS_MAX)
return 0;
if (type <= PERF_SW_EVENTS_MIN)
return 0;
return 1;
}
static char *event_name(int ctr) static char *event_name(int ctr)
{ {
__s64 type = event_id[ctr]; __u64 config = event_id[ctr];
int type = PERF_COUNTER_TYPE(config);
int id = PERF_COUNTER_ID(config);
static char buf[32]; static char buf[32];
if (event_raw[ctr]) { if (PERF_COUNTER_RAW(config)) {
sprintf(buf, "raw 0x%llx", (long long)type); sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config));
return buf; return buf;
} }
if (!type_valid(type))
return "unknown";
if (type >= 0) switch (type) {
return hw_event_names[type]; case PERF_TYPE_HARDWARE:
if (id < PERF_HW_EVENTS_MAX)
return hw_event_names[id];
return "unknown-hardware";
case PERF_TYPE_SOFTWARE:
if (id < PERF_SW_EVENTS_MAX)
return sw_event_names[id];
return "unknown-software";
default:
break;
}
return sw_event_names[-type-1]; return "unknown";
} }
/* /*
* Each event can have multiple symbolic names. * Each event can have multiple symbolic names.
* Symbolic names are (almost) exactly matched. * Symbolic names are (almost) exactly matched.
*/ */
static int match_event_symbols(char *str) static __u64 match_event_symbols(char *str)
{ {
__u64 config, id;
int type;
unsigned int i; unsigned int i;
if (isdigit(str[0]) || str[0] == '-') if (sscanf(str, "r%llx", &config) == 1)
return atoi(str); return config | PERF_COUNTER_RAW_MASK;
if (sscanf(str, "%d:%llu", &type, &id) == 2)
return EID(type, id);
for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
if (!strncmp(str, event_symbols[i].symbol, if (!strncmp(str, event_symbols[i].symbol,
...@@ -294,31 +385,22 @@ static int match_event_symbols(char *str) ...@@ -294,31 +385,22 @@ static int match_event_symbols(char *str)
return event_symbols[i].event; return event_symbols[i].event;
} }
return PERF_HW_EVENTS_MAX; return ~0ULL;
} }
static int parse_events(char *str) static int parse_events(char *str)
{ {
__s64 type; __u64 config;
int raw;
again: again:
if (nr_counters == MAX_COUNTERS) if (nr_counters == MAX_COUNTERS)
return -1; return -1;
raw = 0; config = match_event_symbols(str);
if (*str == 'r') { if (config == ~0ULL)
raw = 1;
++str;
type = strtol(str, NULL, 16);
} else {
type = match_event_symbols(str);
if (!type_valid(type))
return -1; return -1;
}
event_id[nr_counters] = type; event_id[nr_counters] = config;
event_raw[nr_counters] = raw;
nr_counters++; nr_counters++;
str = strstr(str, ","); str = strstr(str, ",");
...@@ -342,8 +424,7 @@ static void create_perfstat_counter(int counter) ...@@ -342,8 +424,7 @@ static void create_perfstat_counter(int counter)
struct perf_counter_hw_event hw_event; struct perf_counter_hw_event hw_event;
memset(&hw_event, 0, sizeof(hw_event)); memset(&hw_event, 0, sizeof(hw_event));
hw_event.type = event_id[counter]; hw_event.config = event_id[counter];
hw_event.raw = event_raw[counter];
hw_event.record_type = PERF_RECORD_SIMPLE; hw_event.record_type = PERF_RECORD_SIMPLE;
hw_event.nmi = 0; hw_event.nmi = 0;
...@@ -428,7 +509,7 @@ int do_perfstat(int argc, char *argv[]) ...@@ -428,7 +509,7 @@ int do_perfstat(int argc, char *argv[])
count += single_count; count += single_count;
} }
if (!event_raw[counter] && if (!PERF_COUNTER_RAW(event_id[counter]) &&
(event_id[counter] == PERF_COUNT_CPU_CLOCK || (event_id[counter] == PERF_COUNT_CPU_CLOCK ||
event_id[counter] == PERF_COUNT_TASK_CLOCK)) { event_id[counter] == PERF_COUNT_TASK_CLOCK)) {
...@@ -911,7 +992,7 @@ static void record_ip(uint64_t ip, int counter) ...@@ -911,7 +992,7 @@ static void record_ip(uint64_t ip, int counter)
assert(left <= middle && middle <= right); assert(left <= middle && middle <= right);
if (!(left <= ip && ip <= right)) { if (!(left <= ip && ip <= right)) {
printf(" left: %016lx\n", left); printf(" left: %016lx\n", left);
printf(" ip: %016lx\n", ip); printf(" ip: %016llx\n", ip);
printf("right: %016lx\n", right); printf("right: %016lx\n", right);
} }
assert(left <= ip && ip <= right); assert(left <= ip && ip <= right);
...@@ -983,7 +1064,7 @@ static void process_options(int argc, char *argv[]) ...@@ -983,7 +1064,7 @@ static void process_options(int argc, char *argv[])
switch (c) { switch (c) {
case 'a': system_wide = 1; break; case 'a': system_wide = 1; break;
case 'c': event_count[nr_counters] = atoi(optarg); break; case 'c': default_interval = atoi(optarg); break;
case 'C': case 'C':
/* CPU and PID are mutually exclusive */ /* CPU and PID are mutually exclusive */
if (tid != -1) { if (tid != -1) {
...@@ -1032,10 +1113,7 @@ static void process_options(int argc, char *argv[]) ...@@ -1032,10 +1113,7 @@ static void process_options(int argc, char *argv[])
if (event_count[counter]) if (event_count[counter])
continue; continue;
if (event_id[counter] < PERF_HW_EVENTS_MAX) event_count[counter] = default_interval;
event_count[counter] = default_count[event_id[counter]];
else
event_count[counter] = 100000;
} }
} }
...@@ -1070,12 +1148,13 @@ int main(int argc, char *argv[]) ...@@ -1070,12 +1148,13 @@ int main(int argc, char *argv[])
cpu = i; cpu = i;
memset(&hw_event, 0, sizeof(hw_event)); memset(&hw_event, 0, sizeof(hw_event));
hw_event.type = event_id[counter]; hw_event.config = event_id[counter];
hw_event.raw = event_raw[counter];
hw_event.irq_period = event_count[counter]; hw_event.irq_period = event_count[counter];
hw_event.record_type = PERF_RECORD_IRQ; hw_event.record_type = PERF_RECORD_IRQ;
hw_event.nmi = nmi; hw_event.nmi = nmi;
printf("FOO: %d %llx %llx\n", counter, event_id[counter], event_count[counter]);
fd[i][counter] = sys_perf_counter_open(&hw_event, tid, cpu, group_fd, 0); fd[i][counter] = sys_perf_counter_open(&hw_event, tid, cpu, group_fd, 0);
fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
if (fd[i][counter] < 0) { if (fd[i][counter] < 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