diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Makefile | 4 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 152 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 368 | ||||
-rw-r--r-- | tools/perf/builtin-test.c | 83 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 221 | ||||
-rw-r--r-- | tools/perf/perf.c | 2 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 123 | ||||
-rw-r--r-- | tools/perf/util/cpumap.h | 10 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 186 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 115 | ||||
-rw-r--r-- | tools/perf/util/header.c | 15 | ||||
-rw-r--r-- | tools/perf/util/header.h | 3 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 58 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 18 | ||||
-rw-r--r-- | tools/perf/util/session.c | 22 | ||||
-rw-r--r-- | tools/perf/util/session.h | 1 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 43 | ||||
-rw-r--r-- | tools/perf/util/thread.h | 15 | ||||
-rw-r--r-- | tools/perf/util/trace-event-info.c | 30 | ||||
-rw-r--r-- | tools/perf/util/trace-event.h | 5 | ||||
-rw-r--r-- | tools/perf/util/util.c | 17 | ||||
-rw-r--r-- | tools/perf/util/util.h | 1 | ||||
-rw-r--r-- | tools/perf/util/xyarray.c | 20 | ||||
-rw-r--r-- | tools/perf/util/xyarray.h | 20 |
24 files changed, 1013 insertions, 519 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ac6692cf550..1b9b13ee2a7 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -396,6 +396,7 @@ LIB_H += util/build-id.h LIB_H += util/debug.h LIB_H += util/debugfs.h LIB_H += util/event.h +LIB_H += util/evsel.h LIB_H += util/exec_cmd.h LIB_H += util/types.h LIB_H += util/levenshtein.h @@ -404,6 +405,7 @@ LIB_H += util/parse-options.h LIB_H += util/parse-events.h LIB_H += util/quote.h LIB_H += util/util.h +LIB_H += util/xyarray.h LIB_H += util/header.h LIB_H += util/help.h LIB_H += util/session.h @@ -433,6 +435,7 @@ LIB_OBJS += $(OUTPUT)util/ctype.o LIB_OBJS += $(OUTPUT)util/debugfs.o LIB_OBJS += $(OUTPUT)util/environment.o LIB_OBJS += $(OUTPUT)util/event.o +LIB_OBJS += $(OUTPUT)util/evsel.o LIB_OBJS += $(OUTPUT)util/exec_cmd.o LIB_OBJS += $(OUTPUT)util/help.o LIB_OBJS += $(OUTPUT)util/levenshtein.o @@ -470,6 +473,7 @@ LIB_OBJS += $(OUTPUT)util/sort.o LIB_OBJS += $(OUTPUT)util/hist.o LIB_OBJS += $(OUTPUT)util/probe-event.o LIB_OBJS += $(OUTPUT)util/util.o +LIB_OBJS += $(OUTPUT)util/xyarray.o LIB_OBJS += $(OUTPUT)util/cpumap.o BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 50efbd509b8..7bc04903548 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -18,6 +18,7 @@ #include "util/header.h" #include "util/event.h" +#include "util/evsel.h" #include "util/debug.h" #include "util/session.h" #include "util/symbol.h" @@ -27,18 +28,18 @@ #include <sched.h> #include <sys/mman.h> +#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) + enum write_mode_t { WRITE_FORCE, WRITE_APPEND }; -static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; - static u64 user_interval = ULLONG_MAX; static u64 default_interval = 0; static u64 sample_type; -static int nr_cpus = 0; +static struct cpu_map *cpus; static unsigned int page_size; static unsigned int mmap_pages = 128; static unsigned int user_freq = UINT_MAX; @@ -53,8 +54,7 @@ static bool sample_id_all_avail = true; static bool system_wide = false; static pid_t target_pid = -1; static pid_t target_tid = -1; -static pid_t *all_tids = NULL; -static int thread_num = 0; +static struct thread_map *threads; static pid_t child_pid = -1; static bool no_inherit = false; static enum write_mode_t write_mode = WRITE_FORCE; @@ -81,7 +81,6 @@ static struct perf_session *session; static const char *cpu_list; struct mmap_data { - int counter; void *base; unsigned int mask; unsigned int prev; @@ -229,12 +228,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n return h_attr; } -static void create_counter(int counter, int cpu) +static void create_counter(struct perf_evsel *evsel, int cpu) { - char *filter = filters[counter]; - struct perf_event_attr *attr = attrs + counter; + char *filter = evsel->filter; + struct perf_event_attr *attr = &evsel->attr; struct perf_header_attr *h_attr; - int track = !counter; /* only the first counter needs these */ + int track = !evsel->idx; /* only the first counter needs these */ int thread_index; int ret; struct { @@ -318,12 +317,11 @@ static void create_counter(int counter, int cpu) retry_sample_id: attr->sample_id_all = sample_id_all_avail ? 1 : 0; - for (thread_index = 0; thread_index < thread_num; thread_index++) { + for (thread_index = 0; thread_index < threads->nr; thread_index++) { try_again: - fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr, - all_tids[thread_index], cpu, group_fd, 0); + FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); - if (fd[nr_cpu][counter][thread_index] < 0) { + if (FD(evsel, nr_cpu, thread_index) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -360,7 +358,7 @@ try_again: } printf("\n"); error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", - fd[nr_cpu][counter][thread_index], strerror(err)); + FD(evsel, nr_cpu, thread_index), strerror(err)); #if defined(__i386__) || defined(__x86_64__) if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) @@ -374,7 +372,7 @@ try_again: exit(-1); } - h_attr = get_header_attr(attr, counter); + h_attr = get_header_attr(attr, evsel->idx); if (h_attr == NULL) die("nomem\n"); @@ -385,7 +383,7 @@ try_again: } } - if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) { + if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { perror("Unable to read perf file descriptor"); exit(-1); } @@ -395,43 +393,44 @@ try_again: exit(-1); } - assert(fd[nr_cpu][counter][thread_index] >= 0); - fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK); + assert(FD(evsel, nr_cpu, thread_index) >= 0); + fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK); /* * First counter acts as the group leader: */ if (group && group_fd == -1) - group_fd = fd[nr_cpu][counter][thread_index]; - - if (counter || thread_index) { - ret = ioctl(fd[nr_cpu][counter][thread_index], - PERF_EVENT_IOC_SET_OUTPUT, - fd[nr_cpu][0][0]); + group_fd = FD(evsel, nr_cpu, thread_index); + + if (evsel->idx || thread_index) { + struct perf_evsel *first; + first = list_entry(evsel_list.next, struct perf_evsel, node); + ret = ioctl(FD(evsel, nr_cpu, thread_index), + PERF_EVENT_IOC_SET_OUTPUT, + FD(first, nr_cpu, 0)); if (ret) { error("failed to set output: %d (%s)\n", errno, strerror(errno)); exit(-1); } } else { - mmap_array[nr_cpu].counter = counter; mmap_array[nr_cpu].prev = 0; mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0); + PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0); if (mmap_array[nr_cpu].base == MAP_FAILED) { error("failed to mmap with %d (%s)\n", errno, strerror(errno)); exit(-1); } - event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; + event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index); event_array[nr_poll].events = POLLIN; nr_poll++; } if (filter != NULL) { - ret = ioctl(fd[nr_cpu][counter][thread_index], - PERF_EVENT_IOC_SET_FILTER, filter); + ret = ioctl(FD(evsel, nr_cpu, thread_index), + PERF_EVENT_IOC_SET_FILTER, filter); if (ret) { error("failed to set filter with %d (%s)\n", errno, strerror(errno)); @@ -446,11 +445,12 @@ try_again: static void open_counters(int cpu) { - int counter; + struct perf_evsel *pos; group_fd = -1; - for (counter = 0; counter < nr_counters; counter++) - create_counter(counter, cpu); + + list_for_each_entry(pos, &evsel_list, node) + create_counter(pos, cpu); nr_cpu++; } @@ -537,7 +537,7 @@ static void mmap_read_all(void) static int __cmd_record(int argc, const char **argv) { - int i, counter; + int i; struct stat st; int flags; int err; @@ -604,7 +604,7 @@ static int __cmd_record(int argc, const char **argv) goto out_delete_session; } - if (have_tracepoints(attrs, nr_counters)) + if (have_tracepoints(&evsel_list)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); /* @@ -652,7 +652,7 @@ static int __cmd_record(int argc, const char **argv) } if (!system_wide && target_tid == -1 && target_pid == -1) - all_tids[0] = child_pid; + threads->map[0] = child_pid; close(child_ready_pipe[1]); close(go_pipe[0]); @@ -666,17 +666,11 @@ static int __cmd_record(int argc, const char **argv) close(child_ready_pipe[0]); } - nr_cpus = read_cpu_map(cpu_list); - if (nr_cpus < 1) { - perror("failed to collect number of CPUs"); - return -1; - } - if (!system_wide && no_inherit && !cpu_list) { open_counters(-1); } else { - for (i = 0; i < nr_cpus; i++) - open_counters(cpumap[i]); + for (i = 0; i < cpus->nr; i++) + open_counters(cpus->map[i]); } perf_session__set_sample_type(session, sample_type); @@ -711,7 +705,7 @@ static int __cmd_record(int argc, const char **argv) return err; } - if (have_tracepoints(attrs, nr_counters)) { + if (have_tracepoints(&evsel_list)) { /* * FIXME err <= 0 here actually means that * there were no tracepoints so its not really @@ -720,8 +714,7 @@ static int __cmd_record(int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ - err = event__synthesize_tracing_data(output, attrs, - nr_counters, + err = event__synthesize_tracing_data(output, &evsel_list, process_synthesized_event, session); if (err <= 0) { @@ -795,13 +788,13 @@ static int __cmd_record(int argc, const char **argv) if (done) { for (i = 0; i < nr_cpu; i++) { - for (counter = 0; - counter < nr_counters; - counter++) { + struct perf_evsel *pos; + + list_for_each_entry(pos, &evsel_list, node) { for (thread = 0; - thread < thread_num; + thread < threads->nr; thread++) - ioctl(fd[i][counter][thread], + ioctl(FD(pos, i, thread), PERF_EVENT_IOC_DISABLE); } } @@ -887,7 +880,8 @@ const struct option record_options[] = { int cmd_record(int argc, const char **argv, const char *prefix __used) { - int i, j, err = -ENOMEM; + int err = -ENOMEM; + struct perf_evsel *pos; argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -910,38 +904,32 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (no_buildid_cache || no_buildid) disable_buildid_cache(); - if (!nr_counters) { - nr_counters = 1; - attrs[0].type = PERF_TYPE_HARDWARE; - attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; + if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { + pr_err("Not enough memory for event selector list\n"); + goto out_symbol_exit; } - if (target_pid != -1) { + if (target_pid != -1) target_tid = target_pid; - thread_num = find_all_tid(target_pid, &all_tids); - if (thread_num <= 0) { - fprintf(stderr, "Can't find all threads of pid %d\n", - target_pid); - usage_with_options(record_usage, record_options); - } - } else { - all_tids=malloc(sizeof(pid_t)); - if (!all_tids) - goto out_symbol_exit; - all_tids[0] = target_tid; - thread_num = 1; + threads = thread_map__new(target_pid, target_tid); + if (threads == NULL) { + pr_err("Problems finding threads of monitor\n"); + usage_with_options(record_usage, record_options); } - for (i = 0; i < MAX_NR_CPUS; i++) { - for (j = 0; j < MAX_COUNTERS; j++) { - fd[i][j] = malloc(sizeof(int)*thread_num); - if (!fd[i][j]) - goto out_free_fd; - } + cpus = cpu_map__new(cpu_list); + if (cpus == NULL) { + perror("failed to parse CPUs map"); + return -1; + } + + list_for_each_entry(pos, &evsel_list, node) { + if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) + goto out_free_fd; } - event_array = malloc( - sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); + event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * + MAX_COUNTERS * threads->nr)); if (!event_array) goto out_free_fd; @@ -968,12 +956,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) out_free_event_array: free(event_array); out_free_fd: - for (i = 0; i < MAX_NR_CPUS; i++) { - for (j = 0; j < MAX_COUNTERS; j++) - free(fd[i][j]); - } - free(all_tids); - all_tids = NULL; + thread_map__delete(threads); + threads = NULL; out_symbol_exit: symbol__exit(); return err; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7ff746da7e6..02b2d8013a6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -43,6 +43,7 @@ #include "util/parse-options.h" #include "util/parse-events.h" #include "util/event.h" +#include "util/evsel.h" #include "util/debug.h" #include "util/header.h" #include "util/cpumap.h" @@ -71,7 +72,7 @@ static struct perf_event_attr default_attrs[] = { }; static bool system_wide = false; -static int nr_cpus = 0; +static struct cpu_map *cpus; static int run_idx = 0; static int run_count = 1; @@ -80,8 +81,7 @@ static bool scale = true; static bool no_aggr = false; static pid_t target_pid = -1; static pid_t target_tid = -1; -static pid_t *all_tids = NULL; -static int thread_num = 0; +static struct thread_map *threads; static pid_t child_pid = -1; static bool null_run = false; static bool big_num = true; @@ -90,17 +90,6 @@ static const char *cpu_list; static const char *csv_sep = NULL; static bool csv_output = false; - -static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; - -static int event_scaled[MAX_COUNTERS]; - -static struct { - u64 val; - u64 ena; - u64 run; -} cpu_counts[MAX_NR_CPUS][MAX_COUNTERS]; - static volatile int done = 0; struct stats @@ -108,6 +97,22 @@ struct stats double n, mean, M2; }; +struct perf_stat { + struct stats res_stats[3]; +}; + +static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) +{ + evsel->priv = zalloc(sizeof(struct perf_stat)); + return evsel->priv == NULL ? -ENOMEM : 0; +} + +static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) +{ + free(evsel->priv); + evsel->priv = NULL; +} + static void update_stats(struct stats *stats, u64 val) { double delta; @@ -147,75 +152,38 @@ static double stddev_stats(struct stats *stats) return sqrt(variance_mean); } -struct stats event_res_stats[MAX_COUNTERS][3]; struct stats runtime_nsecs_stats[MAX_NR_CPUS]; struct stats runtime_cycles_stats[MAX_NR_CPUS]; struct stats runtime_branches_stats[MAX_NR_CPUS]; struct stats walltime_nsecs_stats; -#define MATCH_EVENT(t, c, counter) \ - (attrs[counter].type == PERF_TYPE_##t && \ - attrs[counter].config == PERF_COUNT_##c) - -#define ERR_PERF_OPEN \ -"counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information." - -static int create_perf_stat_counter(int counter, bool *perm_err) +static int create_perf_stat_counter(struct perf_evsel *evsel) { - struct perf_event_attr *attr = attrs + counter; - int thread; - int ncreated = 0; + struct perf_event_attr *attr = &evsel->attr; if (scale) attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; - if (system_wide) { - int cpu; - - for (cpu = 0; cpu < nr_cpus; cpu++) { - fd[cpu][counter][0] = sys_perf_event_open(attr, - -1, cpumap[cpu], -1, 0); - if (fd[cpu][counter][0] < 0) { - if (errno == EPERM || errno == EACCES) - *perm_err = true; - error(ERR_PERF_OPEN, counter, - fd[cpu][counter][0], strerror(errno)); - } else { - ++ncreated; - } - } - } else { - attr->inherit = !no_inherit; - if (target_pid == -1 && target_tid == -1) { - attr->disabled = 1; - attr->enable_on_exec = 1; - } - for (thread = 0; thread < thread_num; thread++) { - fd[0][counter][thread] = sys_perf_event_open(attr, - all_tids[thread], -1, -1, 0); - if (fd[0][counter][thread] < 0) { - if (errno == EPERM || errno == EACCES) - *perm_err = true; - error(ERR_PERF_OPEN, counter, - fd[0][counter][thread], - strerror(errno)); - } else { - ++ncreated; - } - } + if (system_wide) + return perf_evsel__open_per_cpu(evsel, cpus); + + attr->inherit = !no_inherit; + if (target_pid == -1 && target_tid == -1) { + attr->disabled = 1; + attr->enable_on_exec = 1; } - return ncreated; + return perf_evsel__open_per_thread(evsel, threads); } /* * Does the counter have nsecs as a unit? */ -static inline int nsec_counter(int counter) +static inline int nsec_counter(struct perf_evsel *evsel) { - if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || - MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) + if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) || + perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) return 1; return 0; @@ -225,54 +193,17 @@ static inline int nsec_counter(int counter) * Read out the results of a single counter: * aggregate counts across CPUs in system-wide mode */ -static void read_counter_aggr(int counter) +static int read_counter_aggr(struct perf_evsel *counter) { - u64 count[3], single_count[3]; - int cpu; - size_t res, nv; - int scaled; - int i, thread; + struct perf_stat *ps = counter->priv; + u64 *count = counter->counts->aggr.values; + int i; - count[0] = count[1] = count[2] = 0; - - nv = scale ? 3 : 1; - for (cpu = 0; cpu < nr_cpus; cpu++) { - for (thread = 0; thread < thread_num; thread++) { - if (fd[cpu][counter][thread] < 0) - continue; - - res = read(fd[cpu][counter][thread], - single_count, nv * sizeof(u64)); - assert(res == nv * sizeof(u64)); - - close(fd[cpu][counter][thread]); - fd[cpu][counter][thread] = -1; - - count[0] += single_count[0]; - if (scale) { - count[1] += single_count[1]; - count[2] += single_count[2]; - } - } - } - - scaled = 0; - if (scale) { - if (count[2] == 0) { - event_scaled[counter] = -1; - count[0] = 0; - return; - } - - if (count[2] < count[1]) { - event_scaled[counter] = 1; - count[0] = (unsigned long long) - ((double)count[0] * count[1] / count[2] + 0.5); - } - } + if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0) + return -1; for (i = 0; i < 3; i++) - update_stats(&event_res_stats[counter][i], count[i]); + update_stats(&ps->res_stats[i], count[i]); if (verbose) { fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), @@ -282,74 +213,51 @@ static void read_counter_aggr(int counter) /* * Save the full runtime - to allow normalization during printout: */ - if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) + if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) update_stats(&runtime_nsecs_stats[0], count[0]); - if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) + if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[0], count[0]); - if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) + if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) update_stats(&runtime_branches_stats[0], count[0]); + + return 0; } /* * Read out the results of a single counter: * do not aggregate counts across CPUs in system-wide mode */ -static void read_counter(int counter) +static int read_counter(struct perf_evsel *counter) { - u64 count[3]; + u64 *count; int cpu; - size_t res, nv; - - count[0] = count[1] = count[2] = 0; - - nv = scale ? 3 : 1; - - for (cpu = 0; cpu < nr_cpus; cpu++) { - - if (fd[cpu][counter][0] < 0) - continue; - - res = read(fd[cpu][counter][0], count, nv * sizeof(u64)); - - assert(res == nv * sizeof(u64)); - close(fd[cpu][counter][0]); - fd[cpu][counter][0] = -1; + for (cpu = 0; cpu < cpus->nr; cpu++) { + if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) + return -1; - if (scale) { - if (count[2] == 0) { - count[0] = 0; - } else if (count[2] < count[1]) { - count[0] = (unsigned long long) - ((double)count[0] * count[1] / count[2] + 0.5); - } - } - cpu_counts[cpu][counter].val = count[0]; /* scaled count */ - cpu_counts[cpu][counter].ena = count[1]; - cpu_counts[cpu][counter].run = count[2]; + count = counter->counts->cpu[cpu].values; - if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) + if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) update_stats(&runtime_nsecs_stats[cpu], count[0]); - if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) + if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[cpu], count[0]); - if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) + if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) update_stats(&runtime_branches_stats[cpu], count[0]); } + + return 0; } static int run_perf_stat(int argc __used, const char **argv) { unsigned long long t0, t1; + struct perf_evsel *counter; int status = 0; - int counter, ncreated = 0; int child_ready_pipe[2], go_pipe[2]; - bool perm_err = false; const bool forks = (argc > 0); char buf; - if (!system_wide) - nr_cpus = 1; - if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { perror("failed to create pipes"); exit(1); @@ -389,7 +297,7 @@ static int run_perf_stat(int argc __used, const char **argv) } if (target_tid == -1 && target_pid == -1 && !system_wide) - all_tids[0] = child_pid; + threads->map[0] = child_pid; /* * Wait for the child to be ready to exec. @@ -401,19 +309,23 @@ static int run_perf_stat(int argc __used, const char **argv) close(child_ready_pipe[0]); } - for (counter = 0; counter < nr_counters; counter++) - ncreated += create_perf_stat_counter(counter, &perm_err); - - if (ncreated < nr_counters) { - if (perm_err) - error("You may not have permission to collect %sstats.\n" - "\t Consider tweaking" - " /proc/sys/kernel/perf_event_paranoid or running as root.", - system_wide ? "system-wide " : ""); - die("Not all events could be opened.\n"); - if (child_pid != -1) - kill(child_pid, SIGTERM); - return -1; + list_for_each_entry(counter, &evsel_list, node) { + if (create_perf_stat_counter(counter) < 0) { + if (errno == -EPERM || errno == -EACCES) { + error("You may not have permission to collect %sstats.\n" + "\t Consider tweaking" + " /proc/sys/kernel/perf_event_paranoid or running as root.", + system_wide ? "system-wide " : ""); + } else { + error("open_counter returned with %d (%s). " + "/bin/dmesg may provide additional information.\n", + errno, strerror(errno)); + } + if (child_pid != -1) + kill(child_pid, SIGTERM); + die("Not all events could be opened.\n"); + return -1; + } } /* @@ -433,25 +345,33 @@ static int run_perf_stat(int argc __used, const char **argv) update_stats(&walltime_nsecs_stats, t1 - t0); if (no_aggr) { - for (counter = 0; counter < nr_counters; counter++) + list_for_each_entry(counter, &evsel_list, node) { read_counter(counter); + perf_evsel__close_fd(counter, cpus->nr, 1); + } } else { - for (counter = 0; counter < nr_counters; counter++) + list_for_each_entry(counter, &evsel_list, node) { read_counter_aggr(counter); + perf_evsel__close_fd(counter, cpus->nr, threads->nr); + } } + return WEXITSTATUS(status); } -static void print_noise(int counter, double avg) +static void print_noise(struct perf_evsel *evsel, double avg) { + struct perf_stat *ps; + if (run_count == 1) return; + ps = evsel->priv; fprintf(stderr, " ( +- %7.3f%% )", - 100 * stddev_stats(&event_res_stats[counter][0]) / avg); + 100 * stddev_stats(&ps->res_stats[0]) / avg); } -static void nsec_printout(int cpu, int counter, double avg) +static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) { double msecs = avg / 1e6; char cpustr[16] = { '\0', }; @@ -460,20 +380,19 @@ static void nsec_printout(int cpu, int counter, double avg) if (no_aggr) sprintf(cpustr, "CPU%*d%s", csv_output ? 0 : -4, - cpumap[cpu], csv_sep); + cpus->map[cpu], csv_sep); - fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(counter)); + fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); if (csv_output) return; - if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { + if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) fprintf(stderr, " # %10.3f CPUs ", avg / avg_stats(&walltime_nsecs_stats)); - } } -static void abs_printout(int cpu, int counter, double avg) +static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) { double total, ratio = 0.0; char cpustr[16] = { '\0', }; @@ -489,23 +408,23 @@ static void abs_printout(int cpu, int counter, double avg) if (no_aggr) sprintf(cpustr, "CPU%*d%s", csv_output ? 0 : -4, - cpumap[cpu], csv_sep); + cpus->map[cpu], csv_sep); else cpu = 0; - fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(counter)); + fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); if (csv_output) return; - if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { + if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { total = avg_stats(&runtime_cycles_stats[cpu]); if (total) ratio = avg / total; fprintf(stderr, " # %10.3f IPC ", ratio); - } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && + } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && runtime_branches_stats[cpu].n != 0) { total = avg_stats(&runtime_branches_stats[cpu]); @@ -528,10 +447,11 @@ static void abs_printout(int cpu, int counter, double avg) * Print out the results of a single counter: * aggregated counts in system-wide mode */ -static void print_counter_aggr(int counter) +static void print_counter_aggr(struct perf_evsel *counter) { - double avg = avg_stats(&event_res_stats[counter][0]); - int scaled = event_scaled[counter]; + struct perf_stat *ps = counter->priv; + double avg = avg_stats(&ps->res_stats[0]); + int scaled = counter->counts->scaled; if (scaled == -1) { fprintf(stderr, "%*s%s%-24s\n", @@ -555,8 +475,8 @@ static void print_counter_aggr(int counter) if (scaled) { double avg_enabled, avg_running; - avg_enabled = avg_stats(&event_res_stats[counter][1]); - avg_running = avg_stats(&event_res_stats[counter][2]); + avg_enabled = avg_stats(&ps->res_stats[1]); + avg_running = avg_stats(&ps->res_stats[2]); fprintf(stderr, " (scaled from %.2f%%)", 100 * avg_running / avg_enabled); @@ -569,19 +489,19 @@ static void print_counter_aggr(int counter) * Print out the results of a single counter: * does not use aggregated count in system-wide */ -static void print_counter(int counter) +static void print_counter(struct perf_evsel *counter) { u64 ena, run, val; int cpu; - for (cpu = 0; cpu < nr_cpus; cpu++) { - val = cpu_counts[cpu][counter].val; - ena = cpu_counts[cpu][counter].ena; - run = cpu_counts[cpu][counter].run; + for (cpu = 0; cpu < cpus->nr; cpu++) { + val = counter->counts->cpu[cpu].val; + ena = counter->counts->cpu[cpu].ena; + run = counter->counts->cpu[cpu].run; if (run == 0 || ena == 0) { fprintf(stderr, "CPU%*d%s%*s%s%-24s", csv_output ? 0 : -4, - cpumap[cpu], csv_sep, + cpus->map[cpu], csv_sep, csv_output ? 0 : 18, "<not counted>", csv_sep, event_name(counter)); @@ -609,7 +529,8 @@ static void print_counter(int counter) static void print_stat(int argc, const char **argv) { - int i, counter; + struct perf_evsel *counter; + int i; fflush(stdout); @@ -632,10 +553,10 @@ static void print_stat(int argc, const char **argv) } if (no_aggr) { - for (counter = 0; counter < nr_counters; counter++) + list_for_each_entry(counter, &evsel_list, node) print_counter(counter); } else { - for (counter = 0; counter < nr_counters; counter++) + list_for_each_entry(counter, &evsel_list, node) print_counter_aggr(counter); } @@ -720,8 +641,8 @@ static const struct option options[] = { int cmd_stat(int argc, const char **argv, const char *prefix __used) { - int status; - int i,j; + struct perf_evsel *pos; + int status = -ENOMEM; setlocale(LC_ALL, ""); @@ -757,41 +678,45 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) /* Set attrs and nr_counters if no event is selected and !null_run */ if (!null_run && !nr_counters) { - memcpy(attrs, default_attrs, sizeof(default_attrs)); + size_t c; + nr_counters = ARRAY_SIZE(default_attrs); + + for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { + pos = perf_evsel__new(default_attrs[c].type, + default_attrs[c].config, + nr_counters); + if (pos == NULL) + goto out; + list_add(&pos->node, &evsel_list); + } } - if (system_wide) - nr_cpus = read_cpu_map(cpu_list); - else - nr_cpus = 1; + if (target_pid != -1) + target_tid = target_pid; - if (nr_cpus < 1) + threads = thread_map__new(target_pid, target_tid); + if (threads == NULL) { + pr_err("Problems finding threads of monitor\n"); |