Commit a21ca2ca authored by Ingo Molnar's avatar Ingo Molnar

perf_counter: Separate out attr->type from attr->config

Counter type is a frequently used value and we do a lot of
bit juggling by encoding and decoding it from attr->config.

Clean this up by creating a separate attr->type field.

Also clean up the various similarly complex user-space bits
all around counter attribute management.

The net improvement is significant, and it will be easier
to add a new major type (which is what triggered this cleanup).

(This changes the ABI, all tools are adapted.)
(PowerPC build-tested.)

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 2f335a02
...@@ -20,10 +20,10 @@ ...@@ -20,10 +20,10 @@
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) #define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static long default_interval = 100000; static long default_interval = 100000;
static long event_count[MAX_COUNTERS];
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static int nr_cpus = 0; static int nr_cpus = 0;
static unsigned int page_size; static unsigned int page_size;
static unsigned int mmap_pages = 128; static unsigned int mmap_pages = 128;
...@@ -38,15 +38,35 @@ static int inherit = 1; ...@@ -38,15 +38,35 @@ static int inherit = 1;
static int force = 0; static int force = 0;
static int append_file = 0; static int append_file = 0;
const unsigned int default_count[] = { static long samples;
1000000, static struct timeval last_read;
1000000, static struct timeval this_read;
10000,
10000, static __u64 bytes_written;
1000000,
10000, static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
static int nr_poll;
static int nr_cpu;
struct mmap_event {
struct perf_event_header header;
__u32 pid;
__u32 tid;
__u64 start;
__u64 len;
__u64 pgoff;
char filename[PATH_MAX];
};
struct comm_event {
struct perf_event_header header;
__u32 pid;
__u32 tid;
char comm[16];
}; };
struct mmap_data { struct mmap_data {
int counter; int counter;
void *base; void *base;
...@@ -54,6 +74,8 @@ struct mmap_data { ...@@ -54,6 +74,8 @@ struct mmap_data {
unsigned int prev; unsigned int prev;
}; };
static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
static unsigned int mmap_read_head(struct mmap_data *md) static unsigned int mmap_read_head(struct mmap_data *md)
{ {
struct perf_counter_mmap_page *pc = md->base; struct perf_counter_mmap_page *pc = md->base;
...@@ -65,11 +87,6 @@ static unsigned int mmap_read_head(struct mmap_data *md) ...@@ -65,11 +87,6 @@ static unsigned int mmap_read_head(struct mmap_data *md)
return head; return head;
} }
static long samples;
static struct timeval last_read, this_read;
static __u64 bytes_written;
static void mmap_read(struct mmap_data *md) static void mmap_read(struct mmap_data *md)
{ {
unsigned int head = mmap_read_head(md); unsigned int head = mmap_read_head(md);
...@@ -157,29 +174,6 @@ static void sig_handler(int sig) ...@@ -157,29 +174,6 @@ static void sig_handler(int sig)
done = 1; done = 1;
} }
static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
static int nr_poll;
static int nr_cpu;
struct mmap_event {
struct perf_event_header header;
__u32 pid;
__u32 tid;
__u64 start;
__u64 len;
__u64 pgoff;
char filename[PATH_MAX];
};
struct comm_event {
struct perf_event_header header;
__u32 pid;
__u32 tid;
char comm[16];
};
static void pid_synthesize_comm_event(pid_t pid, int full) static void pid_synthesize_comm_event(pid_t pid, int full)
{ {
struct comm_event comm_ev; struct comm_event comm_ev;
...@@ -341,24 +335,21 @@ static int group_fd; ...@@ -341,24 +335,21 @@ static int group_fd;
static void create_counter(int counter, int cpu, pid_t pid) static void create_counter(int counter, int cpu, pid_t pid)
{ {
struct perf_counter_attr attr; struct perf_counter_attr *attr = attrs + counter;
int track = 1; int track = 1;
memset(&attr, 0, sizeof(attr)); attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD;
attr.config = event_id[counter];
attr.sample_period = event_count[counter];
attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD;
if (freq) { if (freq) {
attr.freq = 1; attr->freq = 1;
attr.sample_freq = freq; attr->sample_freq = freq;
} }
attr.mmap = track; attr->mmap = track;
attr.comm = track; attr->comm = track;
attr.inherit = (cpu < 0) && inherit; attr->inherit = (cpu < 0) && inherit;
track = 0; /* only the first counter needs these */ track = 0; /* only the first counter needs these */
fd[nr_cpu][counter] = sys_perf_counter_open(&attr, pid, cpu, group_fd, 0); fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
if (fd[nr_cpu][counter] < 0) { if (fd[nr_cpu][counter] < 0) {
int err = errno; int err = errno;
...@@ -542,16 +533,14 @@ int cmd_record(int argc, const char **argv, const char *prefix) ...@@ -542,16 +533,14 @@ int cmd_record(int argc, const char **argv, const char *prefix)
if (!argc && target_pid == -1 && !system_wide) if (!argc && target_pid == -1 && !system_wide)
usage_with_options(record_usage, options); usage_with_options(record_usage, options);
if (!nr_counters) { if (!nr_counters)
nr_counters = 1; nr_counters = 1;
event_id[0] = 0;
}
for (counter = 0; counter < nr_counters; counter++) { for (counter = 0; counter < nr_counters; counter++) {
if (event_count[counter]) if (attrs[counter].sample_period)
continue; continue;
event_count[counter] = default_interval; attrs[counter].sample_period = default_interval;
} }
return __cmd_record(argc, argv); return __cmd_record(argc, argv);
......
...@@ -44,23 +44,22 @@ ...@@ -44,23 +44,22 @@
#include <sys/prctl.h> #include <sys/prctl.h>
static int system_wide = 0; static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
static int inherit = 1;
static __u64 default_event_id[MAX_COUNTERS] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_TASK_CLOCK },
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_CONTEXT_SWITCHES },
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_CPU_MIGRATIONS },
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_PAGE_FAULTS },
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CPU_CYCLES },
EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_INSTRUCTIONS },
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CACHE_REFERENCES },
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CACHE_MISSES },
}; };
static int default_interval = 100000; static int system_wide = 0;
static int event_count[MAX_COUNTERS]; static int inherit = 1;
static int fd[MAX_NR_CPUS][MAX_COUNTERS]; static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static int target_pid = -1; static int target_pid = -1;
...@@ -86,22 +85,16 @@ static __u64 walltime_nsecs; ...@@ -86,22 +85,16 @@ static __u64 walltime_nsecs;
static void create_perfstat_counter(int counter) static void create_perfstat_counter(int counter)
{ {
struct perf_counter_attr attr; struct perf_counter_attr *attr = attrs + counter;
memset(&attr, 0, sizeof(attr));
attr.config = event_id[counter];
attr.sample_type = 0;
attr.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL;
attr.exclude_user = event_mask[counter] & EVENT_MASK_USER;
if (scale) if (scale)
attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
PERF_FORMAT_TOTAL_TIME_RUNNING; PERF_FORMAT_TOTAL_TIME_RUNNING;
if (system_wide) { if (system_wide) {
int cpu; int cpu;
for (cpu = 0; cpu < nr_cpus; cpu ++) { for (cpu = 0; cpu < nr_cpus; cpu ++) {
fd[cpu][counter] = sys_perf_counter_open(&attr, -1, cpu, -1, 0); fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
if (fd[cpu][counter] < 0) { if (fd[cpu][counter] < 0) {
printf("perfstat error: syscall returned with %d (%s)\n", printf("perfstat error: syscall returned with %d (%s)\n",
fd[cpu][counter], strerror(errno)); fd[cpu][counter], strerror(errno));
...@@ -109,10 +102,10 @@ static void create_perfstat_counter(int counter) ...@@ -109,10 +102,10 @@ static void create_perfstat_counter(int counter)
} }
} }
} else { } else {
attr.inherit = inherit; attr->inherit = inherit;
attr.disabled = 1; attr->disabled = 1;
fd[0][counter] = sys_perf_counter_open(&attr, 0, -1, -1, 0); fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0);
if (fd[0][counter] < 0) { if (fd[0][counter] < 0) {
printf("perfstat error: syscall returned with %d (%s)\n", printf("perfstat error: syscall returned with %d (%s)\n",
fd[0][counter], strerror(errno)); fd[0][counter], strerror(errno));
...@@ -126,9 +119,13 @@ static void create_perfstat_counter(int counter) ...@@ -126,9 +119,13 @@ static void create_perfstat_counter(int counter)
*/ */
static inline int nsec_counter(int counter) static inline int nsec_counter(int counter)
{ {
if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK)) if (attrs[counter].type != PERF_TYPE_SOFTWARE)
return 0;
if (attrs[counter].config == PERF_COUNT_CPU_CLOCK)
return 1; return 1;
if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK))
if (attrs[counter].config == PERF_COUNT_TASK_CLOCK)
return 1; return 1;
return 0; return 0;
...@@ -177,7 +174,8 @@ static void read_counter(int counter) ...@@ -177,7 +174,8 @@ static void read_counter(int counter)
/* /*
* Save the full runtime - to allow normalization during printout: * Save the full runtime - to allow normalization during printout:
*/ */
if (event_id[counter] == EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK)) if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
attrs[counter].config == PERF_COUNT_TASK_CLOCK)
runtime_nsecs = count[0]; runtime_nsecs = count[0];
} }
...@@ -203,8 +201,8 @@ static void print_counter(int counter) ...@@ -203,8 +201,8 @@ static void print_counter(int counter)
fprintf(stderr, " %14.6f %-20s", fprintf(stderr, " %14.6f %-20s",
msecs, event_name(counter)); msecs, event_name(counter));
if (event_id[counter] == if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK)) { attrs[counter].config == PERF_COUNT_TASK_CLOCK) {
fprintf(stderr, " # %11.3f CPU utilization factor", fprintf(stderr, " # %11.3f CPU utilization factor",
(double)count[0] / (double)walltime_nsecs); (double)count[0] / (double)walltime_nsecs);
...@@ -300,8 +298,6 @@ static char events_help_msg[EVENTS_HELP_MAX]; ...@@ -300,8 +298,6 @@ static char events_help_msg[EVENTS_HELP_MAX];
static const struct option options[] = { static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event", OPT_CALLBACK('e', "event", NULL, "event",
events_help_msg, parse_events), events_help_msg, parse_events),
OPT_INTEGER('c', "count", &default_interval,
"event period to sample"),
OPT_BOOLEAN('i', "inherit", &inherit, OPT_BOOLEAN('i', "inherit", &inherit,
"child tasks inherit counters"), "child tasks inherit counters"),
OPT_INTEGER('p', "pid", &target_pid, OPT_INTEGER('p', "pid", &target_pid,
...@@ -315,27 +311,19 @@ static const struct option options[] = { ...@@ -315,27 +311,19 @@ static const struct option options[] = {
int cmd_stat(int argc, const char **argv, const char *prefix) int cmd_stat(int argc, const char **argv, const char *prefix)
{ {
int counter;
page_size = sysconf(_SC_PAGE_SIZE); page_size = sysconf(_SC_PAGE_SIZE);
create_events_help(events_help_msg); create_events_help(events_help_msg);
memcpy(event_id, default_event_id, sizeof(default_event_id));
memcpy(attrs, default_attrs, sizeof(attrs));
argc = parse_options(argc, argv, options, stat_usage, 0); argc = parse_options(argc, argv, options, stat_usage, 0);
if (!argc) if (!argc)
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
if (!nr_counters) { if (!nr_counters)
nr_counters = 8; nr_counters = 8;
}
for (counter = 0; counter < nr_counters; counter++) {
if (event_count[counter])
continue;
event_count[counter] = default_interval;
}
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
assert(nr_cpus <= MAX_NR_CPUS); assert(nr_cpus <= MAX_NR_CPUS);
assert(nr_cpus >= 0); assert(nr_cpus >= 0);
......
...@@ -48,22 +48,11 @@ ...@@ -48,22 +48,11 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/types.h> #include <linux/types.h>
static int system_wide = 0; static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static __u64 default_event_id[MAX_COUNTERS] = { static int system_wide = 0;
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
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 default_interval = 100000;
static int event_count[MAX_COUNTERS];
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static __u64 count_filter = 5; static __u64 count_filter = 5;
static int print_entries = 15; static int print_entries = 15;
...@@ -85,15 +74,6 @@ static int delay_secs = 2; ...@@ -85,15 +74,6 @@ static int delay_secs = 2;
static int zero; static int zero;
static int dump_symtab; static int dump_symtab;
static const unsigned int default_count[] = {
1000000,
1000000,
10000,
10000,
1000000,
10000,
};
/* /*
* Symbols * Symbols
*/ */
...@@ -213,7 +193,7 @@ static void print_sym_table(void) ...@@ -213,7 +193,7 @@ static void print_sym_table(void)
100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
if (nr_counters == 1) { if (nr_counters == 1) {
printf("%d", event_count[0]); printf("%Ld", attrs[0].sample_period);
if (freq) if (freq)
printf("Hz "); printf("Hz ");
else else
...@@ -539,7 +519,7 @@ static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; ...@@ -539,7 +519,7 @@ static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
static int __cmd_top(void) static int __cmd_top(void)
{ {
struct perf_counter_attr attr; struct perf_counter_attr *attr;
pthread_t thread; 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;
...@@ -553,13 +533,12 @@ static int __cmd_top(void) ...@@ -553,13 +533,12 @@ static int __cmd_top(void)
if (target_pid == -1 && profile_cpu == -1) if (target_pid == -1 && profile_cpu == -1)
cpu = i; cpu = i;
memset(&attr, 0, sizeof(attr)); attr = attrs + counter;
attr.config = event_id[counter];
attr.sample_period = event_count[counter]; attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; attr->freq = freq;
attr.freq = freq;
fd[i][counter] = sys_perf_counter_open(&attr, target_pid, cpu, group_fd, 0); fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
if (fd[i][counter] < 0) { if (fd[i][counter] < 0) {
int err = errno; int err = errno;
...@@ -670,7 +649,6 @@ int cmd_top(int argc, const char **argv, const char *prefix) ...@@ -670,7 +649,6 @@ int cmd_top(int argc, const char **argv, const char *prefix)
page_size = sysconf(_SC_PAGE_SIZE); page_size = sysconf(_SC_PAGE_SIZE);
create_events_help(events_help_msg); create_events_help(events_help_msg);
memcpy(event_id, default_event_id, sizeof(default_event_id));
argc = parse_options(argc, argv, options, top_usage, 0); argc = parse_options(argc, argv, options, top_usage, 0);
if (argc) if (argc)
...@@ -688,19 +666,22 @@ int cmd_top(int argc, const char **argv, const char *prefix) ...@@ -688,19 +666,22 @@ int cmd_top(int argc, const char **argv, const char *prefix)
profile_cpu = -1; profile_cpu = -1;
} }
if (!nr_counters) { if (!nr_counters)
nr_counters = 1; nr_counters = 1;
event_id[0] = 0;
}
if (delay_secs < 1) if (delay_secs < 1)
delay_secs = 1; delay_secs = 1;
parse_symbols();
/*
* Fill in the ones not specifically initialized via -c:
*/
for (counter = 0; counter < nr_counters; counter++) { for (counter = 0; counter < nr_counters; counter++) {
if (event_count[counter]) if (attrs[counter].sample_period)
continue; continue;
event_count[counter] = default_interval; attrs[counter].sample_period = default_interval;
} }
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
...@@ -710,7 +691,5 @@ int cmd_top(int argc, const char **argv, const char *prefix) ...@@ -710,7 +691,5 @@ int cmd_top(int argc, const char **argv, const char *prefix)
if (target_pid != -1 || profile_cpu != -1) if (target_pid != -1 || profile_cpu != -1)
nr_cpus = 1; nr_cpus = 1;
parse_symbols();
return __cmd_top(); return __cmd_top();
} }
...@@ -64,6 +64,4 @@ sys_perf_counter_open(struct perf_counter_attr *attr_uptr, ...@@ -64,6 +64,4 @@ sys_perf_counter_open(struct perf_counter_attr *attr_uptr,
#define MAX_COUNTERS 256 #define MAX_COUNTERS 256
#define MAX_NR_CPUS 256 #define MAX_NR_CPUS 256
#define EID(type, id) (((__u64)(type) << PERF_COUNTER_TYPE_SHIFT) | (id))
#endif #endif
...@@ -8,35 +8,37 @@ ...@@ -8,35 +8,37 @@
int nr_counters; int nr_counters;
__u64 event_id[MAX_COUNTERS] = { }; struct perf_counter_attr attrs[MAX_COUNTERS];
int event_mask[MAX_COUNTERS];
struct event_symbol { struct event_symbol {
__u64 event; __u8 type;
__u64 config;
char *symbol; char *symbol;
}; };
#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y
static struct event_symbol event_symbols[] = { static struct event_symbol event_symbols[] = {
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", }, { C(HARDWARE, CPU_CYCLES), "cpu-cycles", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", }, { C(HARDWARE, CPU_CYCLES), "cycles", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", }, { C(HARDWARE, INSTRUCTIONS), "instructions", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", }, { C(HARDWARE, CACHE_REFERENCES), "cache-references", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", }, { C(HARDWARE, CACHE_MISSES), "cache-misses", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", }, { C(HARDWARE, BRANCH_INSTRUCTIONS), "branch-instructions", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", }, { C(HARDWARE, BRANCH_INSTRUCTIONS), "branches", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", }, { C(HARDWARE, BRANCH_MISSES), "branch-misses", },
{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", }, { C(HARDWARE, BUS_CYCLES), "bus-cycles", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", }, { C(SOFTWARE, CPU_CLOCK), "cpu-clock", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", }, { C(SOFTWARE, TASK_CLOCK), "task-clock", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", }, { C(SOFTWARE, PAGE_FAULTS), "page-faults", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", }, { C(SOFTWARE, PAGE_FAULTS), "faults", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", }, { C(SOFTWARE, PAGE_FAULTS_MIN), "minor-faults", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", }, { C(SOFTWARE, PAGE_FAULTS_MAJ), "major-faults", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", }, { C(SOFTWARE, CONTEXT_SWITCHES), "context-switches", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", }, { C(SOFTWARE, CONTEXT_SWITCHES), "cs", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", }, { C(SOFTWARE, CPU_MIGRATIONS), "cpu-migrations", },
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", }, { C(SOFTWARE, CPU_MIGRATIONS), "migrations", },
}; };
#define __PERF_COUNTER_FIELD(config, name) \ #define __PERF_COUNTER_FIELD(config, name) \
...@@ -67,27 +69,26 @@ static char *sw_event_names[] = { ...@@ -67,27 +69,26 @@ static char *sw_event_names[] = {
"major faults", "major faults",
}; };
char *event_name(int ctr) char *event_name(int counter)
{ {
__u64 config = event_id[ctr]; __u64 config = attrs[counter].config;
int type = PERF_COUNTER_TYPE(config); int type = attrs[counter].type;
int id = PERF_COUNTER_ID(config);
static char buf[32]; static char buf[32];
if (PERF_COUNTER_RAW(config)) { if (attrs[counter].type == PERF_TYPE_RAW) {
sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config)); sprintf(buf, "raw 0x%llx", config);
return buf; return buf;
} }
switch (type) { switch (type) {
case PERF_TYPE_HARDWARE: case PERF_TYPE_HARDWARE:
if (id < PERF_HW_EVENTS_MAX) if (config < PERF_HW_EVENTS_MAX)
return hw_event_names[id]; return hw_event_names[config];
return "unknown-hardware"; return "unknown-hardware";
case PERF_TYPE_SOFTWARE: case PERF_TYPE_SOFTWARE:
if (id < PERF_SW_EVENTS_MAX) if (config < PERF_SW_EVENTS_MAX)
return sw_event_names[id]; return sw_event_names[config];
return "unknown-software"; return "unknown-software";
default: default:
...@@ -101,15 +102,19 @@ char *event_name(int ctr) ...@@ -101,15 +102,19 @@ char *event_name(int ctr)
* 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 __u64 match_event_symbols(const char *str) static int match_event_symbols(const char *str, struct perf_counter_attr *attr)
{ {
__u64 config, id; __u64 config, id;
int type; int type;
unsigned int i; unsigned int i;
const char *sep, *pstr; const char *sep, *pstr;
if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
return config | PERF_COUNTER_RAW_MASK; attr->type = PERF_TYPE_RAW;
attr->config = config;
return 0;
}
pstr = str; pstr = str;
sep = strchr(pstr, ':'); sep = strchr(pstr, ':');
...@@ -121,35 +126,45 @@ static __u64 match_event_symbols(const char *str) ...@@ -121,35 +126,45 @@ static __u64 match_event_symbols(const char *str)
if (sep) { if (sep) {
pstr = sep + 1; pstr = sep + 1;
if (strchr(pstr, 'k')) if (strchr(pstr, 'k'))
event_mask[nr_counters] |= EVENT_MASK_USER; attr->exclude_user = 1;
if (strchr(pstr, 'u')) if (strchr(pstr, 'u'))
event_mask[nr_counters] |= EVENT_MASK_KERNEL; attr->exclude_kernel = 1;
} }
return EID(type, id); attr->type = type;
attr->config = id;
return 0;
} }
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,
strlen(event_symbols[i].symbol))) strlen(event_symbols[i].symbol))) {
return event_symbols[i].event;
attr->type = event_symbols[i].type;
attr->config = event_symbols[i].config;
return 0;
}
} }
return ~0ULL; return -EINVAL;
} }
int parse_events(const struct option *opt, const char *str, int unset) int parse_events(const struct option *opt, const char *str, int unset)
{ {
__u64 config; struct perf_counter_attr attr;
int ret;
memset(&attr, 0, sizeof(attr));
again: again:
if (nr_counters == MAX_COUNTERS) if (nr_counters == MAX_COUNTERS)
return -1; return -1;
config = match_event_symbols(str); ret = match_event_symbols(str, &attr);
if (config == ~0ULL) if (ret < 0)
return -1; return ret;
event_id[nr_counters] = config; attrs[nr_counters] = attr;
nr_counters++; nr_counters++;
str = strstr(str, ","); str = strstr(str, ",");
...@@ -168,7 +183,6 @@ void create_events_help(char *events_help_msg) ...@@ -168,7 +183,6 @@ void create_events_help(char *events_help_msg)
{ {
unsigned int i; unsigned int i;
char *str; char *str;
__u64 e;
str = events_help_msg; str = events_help_msg;
...@@ -178,9 +192,8 @@ void create_events_help(char *events_help_msg) ...@@ -178,9 +192,8 @@ void create_events_help(char *events_help_msg)
for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
int type, id; int type, id;
e = event_symbols[i].event; type = event_symbols[i].type;
type = PERF_COUNTER_TYPE(e); id = event_symbols[i].config;
id = PERF_COUNTER_ID(e);
if (i) if (i)
str += sprintf(str, "|"); str += sprintf(str, "|");
...@@ -191,4 +204,3 @@ void create_events_help(char *events_help_msg) ...@@ -191,4 +204,3 @@ void create_events_help(char *events_help_msg)
str += sprintf(str, "|rNNN]"); str += sprintf(str, "|rNNN]");
} }
...@@ -4,11 +4,8 @@ ...@@ -4,11 +4,8 @@
*/ */
extern int nr_counters; extern int nr_counters;
extern __u64 event_id[MAX_COUNTERS];
extern int event_mask[MAX_COUNTERS];
#define EVENT_MASK_KERNEL 1 extern struct perf_counter_attr attrs[MAX_COUNTERS];
#define EVENT_MASK_USER 2
extern char *event_name(int ctr); extern char *event_name(int ctr);
......
...@@ -867,13 +867,13 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter) ...@@ -867,13 +867,13 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter)
if (!ppmu) if (!ppmu)
return ERR_PTR(-ENXIO); return ERR_PTR(-ENXIO);
if (!perf_event_raw(&counter->attr)) { if (counter->attr.type != PERF_TYPE_RAW) {
ev = perf_event_id(&counter->attr); ev = counter->attr.config;
if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0) if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
ev = ppmu->generic_events[ev]; ev = ppmu->generic_events[ev];
} else { } else {
ev = perf_event_config(&counter->attr); ev = counter->attr.config;
} }
counter->hw.config_base = ev; counter->hw.config_base = ev;
counter->hw.idx = 0; counter->hw.idx = 0;
......
...@@ -292,15 +292,15 @@ static int __hw_perf_counter_init(struct perf_counter *counter) ...@@ -292,15 +292,15 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
/* /*
* Raw event type provide the config in the event structure * Raw event type provide the config in the event structure
*/ */
if (perf_event_raw(attr)) { if (attr->type == PERF_TYPE_RAW) {
hwc->config |= x86_pmu.raw_event(perf_event_config(attr)); hwc->config |= x86_pmu.raw_event(attr->config);
} else { } else {
if (perf_event_id(attr) >= x86_pmu.max_events) if (attr->config >= x86_pmu.max_events)
return -EINVAL; return -EINVAL;
/* /*
* The generic map: * The generic map:
*/ */
hwc->config |= x86_pmu.event_map(perf_event_id(attr)); hwc->config |= x86_pmu.event_map(attr->config);
} }
counter->destroy = hw_perf_counter_destroy; counter->destroy = hw_perf_counter_destroy;
......
...@@ -73,26 +73,6 @@ enum sw_event_ids { ...@@ -73,26 +73,6 @@ enum sw_event_ids {
PERF_SW_EVENTS_MAX = 7, PERF_SW_EVENTS_MAX = 7,
}; };
#define __PERF_COUNTER_MASK(name) \
(((1ULL << PERF_COUNTER_##name##_BITS) - 1) << \
PERF_COUNTER_##name##_SHIFT)
#define PERF_COUNTER_RAW_BITS 1
#define PERF_COUNTER_RAW_SHIFT 63
#define PERF_COUNTER_RAW_MASK __PERF_COUNTER_MASK(RAW)
#define PERF_COUNTER_CONFIG_BITS 63
#define PERF_COUNTER_CONFIG_SHIFT 0
#define PERF_COUNTER_CONFIG_MASK __PERF_COUNTER_MASK(CONFIG)
#define PERF_COUNTER_TYPE_BITS 7
#define PERF_COUNTER_TYPE_SHIFT 56
#define PERF_COUNTER_TYPE_MASK __PERF_COUNTER_MASK(TYPE)
#define PERF_COUNTER_EVENT_BITS 56
#define PERF_COUNTER_EVENT_SHIFT 0
#define PERF_COUNTER_EVENT_MASK __PERF_COUNTER_MASK(EVENT)
/* /*
* Bits that can be set in attr.sample_type to request information * Bits that can be set in attr.sample_type to request information
* in the overflow packets. * in the overflow packets.
...@@ -125,10 +105,13 @@ enum perf_counter_read_format { ...@@ -125,10 +105,13 @@ enum perf_counter_read_format {
*/ */
struct perf_counter_attr { struct perf_counter_attr {
/* /*
* The MSB of the config word signifies if the rest contains cpu * Major type: hardware/software/tracepoint/etc.
* specific (raw) counter configuration data, if unset, the next */
* 7 bits are an event type and the rest of the bits are the event __u32 type;
* identifier. __u32 __reserved_1;
/*
* Type specific configuration information.
*/ */
__u64 config; __u64 config;
...@@ -152,12 +135,11 @@ struct perf_counter_attr { ...@@ -152,12 +135,11 @@ struct perf_counter_attr {
comm : 1, /* include comm data */ comm : 1, /* include comm data */
freq : 1, /* use freq, not period */ freq : 1, /* use freq, not period */
__reserved_1 : 53; __reserved_2 : 53;
__u32 wakeup_events; /* wakeup every n events */ __u32 wakeup_events; /* wakeup every n events */
__u32 __reserved_2; __u32 __reserved_3;
__u64 __reserved_3;
__u64 __reserved_4; __u64 __reserved_4;
}; };
...@@ -331,27 +313,6 @@ enum perf_event_type { ...@@ -331,27 +313,6 @@ enum perf_event_type {
struct task_struct; struct task_struct;
static inline u64 perf_event_raw(struct perf_counter_attr *attr)
{
return attr->config & PERF_COUNTER_RAW_MASK;
}
static inline u64 perf_event_config(struct perf_counter_attr *attr)
{
return attr->config & PERF_COUNTER_CONFIG_MASK;
}
static inline u64 perf_event_type(struct perf_counter_attr *attr)
{
return (attr->config & PERF_COUNTER_TYPE_MASK) >>
PERF_COUNTER_TYPE_SHIFT;
}
static inline u64 perf_event_id(struct perf_counter_attr *attr)
{
return attr->config & PERF_COUNTER_EVENT_MASK;
}
/** /**
* struct hw_perf_counter - performance counter hardware details: * struct hw_perf_counter - performance counter hardware details:
*/ */
...@@ -616,8 +577,8 @@ extern int perf_counter_overflow(struct perf_counter *counter, ...@@ -616,8 +577,8 @@ extern int perf_counter_overflow(struct perf_counter *counter,
*/ */
static inline int is_software_counter(struct perf_counter *counter) static inline int is_software_counter(struct perf_counter *counter)
{ {
return !perf_event_raw(&counter->attr) && return (counter->attr.type != PERF_TYPE_RAW) &&
perf_event_type(&counter->attr) != PERF_TYPE_HARDWARE; (counter->attr.type != PERF_TYPE_HARDWARE);
} }
extern void perf_swcounter_event(u32, u64, int, struct pt_regs *, u64); extern void perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
......
...@@ -3091,14 +3091,12 @@ static int perf_swcounter_match(struct perf_counter *counter, ...@@ -3091,14 +3091,12 @@ static int perf_swcounter_match(struct perf_counter *counter,
enum perf_event_types type, enum perf_event_types type,
u32 event, struct pt_regs *regs) u32 event, struct pt_regs *regs)
{ {
u64 event_config;
event_config = ((u64) type << PERF_COUNTER_TYPE_SHIFT) | event;
if (!perf_swcounter_is_counting(counter)) if (!perf_swcounter_is_counting(counter))
return 0; return 0;
if (counter->attr.config != event_config) if (counter->attr.type != type)
return 0;
if (counter->attr.config != event)
return 0; return 0;
if (regs) { if (regs) {
...@@ -3403,7 +3401,7 @@ static const struct pmu *sw_perf_counter_init(struct perf_counter *counter) ...@@ -3403,7 +3401,7 @@ static const struct pmu *sw_perf_counter_init(struct perf_counter *counter)
* to be kernel events, and page faults are never hypervisor * to be kernel events, and page faults are never hypervisor
* events. * events.
*/ */
switch (perf_event_id(&counter->attr)) { switch (counter->attr.config) {
case PERF_COUNT_CPU_CLOCK: case PERF_COUNT_CPU_CLOCK:
pmu = &perf_ops_cpu_clock; pmu = &perf_ops_cpu_clock;
...@@ -3496,12 +3494,12 @@ perf_counter_alloc(struct perf_counter_attr *attr, ...@@ -3496,12 +3494,12 @@ perf_counter_alloc(struct perf_counter_attr *attr,
if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP)) if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP))
goto done; goto done;
if (perf_event_raw(attr)) { if (attr->type == PERF_TYPE_RAW) {
pmu = hw_perf_counter_init(counter); pmu = hw_perf_counter_init(counter);
goto done; goto done;
} }
switch (perf_event_type(attr)) { switch (attr->type) {
case PERF_TYPE_HARDWARE: case PERF_TYPE_HARDWARE:
pmu = hw_perf_counter_init(counter); pmu = hw_perf_counter_init(counter);
break; break;
......
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