From 361c99a661a78ed22264649440e87fe4fe8da1f2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Jan 2011 20:56:53 -0200 Subject: perf evsel: Introduce perf_evlist Killing two more perf wide global variables: nr_counters and evsel_list as a list_head. There are more operations that will need more fields in perf_evlist, like the pollfd for polling all the fds in a list of evsel instances. Use option->value to pass the evsel_list to parse_{events,filters}. LKML-Reference: Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 47 +++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b2f729f..252ace8 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/evlist.h" #include "util/evsel.h" #include "util/debug.h" #include "util/session.h" @@ -66,6 +67,7 @@ static bool sample_address = false; static bool sample_time = false; static bool no_buildid = false; static bool no_buildid_cache = false; +static struct perf_evlist *evsel_list; static long samples = 0; static u64 bytes_written = 0; @@ -229,7 +231,8 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n return h_attr; } -static void create_counter(struct perf_evsel *evsel, int cpu) +static void create_counter(struct perf_evlist *evlist, + struct perf_evsel *evsel, int cpu) { char *filter = evsel->filter; struct perf_event_attr *attr = &evsel->attr; @@ -263,7 +266,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu) attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; - if (nr_counters > 1) + if (evlist->nr_entries > 1) attr->sample_type |= PERF_SAMPLE_ID; /* @@ -410,7 +413,7 @@ try_again: if (evsel->idx || thread_index) { struct perf_evsel *first; - first = list_entry(evsel_list.next, struct perf_evsel, node); + first = list_entry(evlist->entries.next, struct perf_evsel, node); ret = ioctl(FD(evsel, nr_cpu, thread_index), PERF_EVENT_IOC_SET_OUTPUT, FD(first, nr_cpu, 0)); @@ -449,14 +452,14 @@ try_again: sample_type = attr->sample_type; } -static void open_counters(int cpu) +static void open_counters(struct perf_evlist *evlist, int cpu) { struct perf_evsel *pos; group_fd = -1; - list_for_each_entry(pos, &evsel_list, node) - create_counter(pos, cpu); + list_for_each_entry(pos, &evlist->entries, node) + create_counter(evlist, pos, cpu); nr_cpu++; } @@ -481,9 +484,9 @@ static void atexit_header(void) if (!no_buildid) process_buildids(); - perf_header__write(&session->header, output, true); + perf_header__write(&session->header, evsel_list, output, true); perf_session__delete(session); - perf_evsel_list__delete(); + perf_evlist__delete(evsel_list); symbol__exit(); } } @@ -611,7 +614,7 @@ static int __cmd_record(int argc, const char **argv) goto out_delete_session; } - if (have_tracepoints(&evsel_list)) + if (have_tracepoints(&evsel_list->entries)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); /* @@ -674,10 +677,10 @@ static int __cmd_record(int argc, const char **argv) } if (!system_wide && no_inherit && !cpu_list) { - open_counters(-1); + open_counters(evsel_list, -1); } else { for (i = 0; i < cpus->nr; i++) - open_counters(cpus->map[i]); + open_counters(evsel_list, cpus->map[i]); } perf_session__set_sample_type(session, sample_type); @@ -687,7 +690,8 @@ static int __cmd_record(int argc, const char **argv) if (err < 0) return err; } else if (file_new) { - err = perf_header__write(&session->header, output, false); + err = perf_header__write(&session->header, evsel_list, + output, false); if (err < 0) return err; } @@ -712,7 +716,7 @@ static int __cmd_record(int argc, const char **argv) return err; } - if (have_tracepoints(&evsel_list)) { + if (have_tracepoints(&evsel_list->entries)) { /* * FIXME err <= 0 here actually means that * there were no tracepoints so its not really @@ -721,7 +725,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, &evsel_list, + err = event__synthesize_tracing_data(output, evsel_list, process_synthesized_event, session); if (err <= 0) { @@ -797,7 +801,7 @@ static int __cmd_record(int argc, const char **argv) for (i = 0; i < nr_cpu; i++) { struct perf_evsel *pos; - list_for_each_entry(pos, &evsel_list, node) { + list_for_each_entry(pos, &evsel_list->entries, node) { for (thread = 0; thread < threads->nr; thread++) @@ -838,10 +842,10 @@ static const char * const record_usage[] = { static bool force, append_file; const struct option record_options[] = { - OPT_CALLBACK('e', "event", NULL, "event", + OPT_CALLBACK('e', "event", &evsel_list, "event", "event selector. use 'perf list' to list available events", parse_events), - OPT_CALLBACK(0, "filter", NULL, "filter", + OPT_CALLBACK(0, "filter", &evsel_list, "filter", "event filter", parse_filter), OPT_INTEGER('p', "pid", &target_pid, "record events on existing process id"), @@ -892,6 +896,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) int err = -ENOMEM; struct perf_evsel *pos; + evsel_list = perf_evlist__new(); + if (evsel_list == NULL) + return -ENOMEM; + argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target_pid == -1 && target_tid == -1 && @@ -913,7 +921,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (no_buildid_cache || no_buildid) disable_buildid_cache(); - if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { + if (evsel_list->nr_entries == 0 && + perf_evlist__add_default(evsel_list) < 0) { pr_err("Not enough memory for event selector list\n"); goto out_symbol_exit; } @@ -933,7 +942,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) return -1; } - list_for_each_entry(pos, &evsel_list, node) { + list_for_each_entry(pos, &evsel_list->entries, node) { if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; if (perf_header__push_event(pos->attr.config, event_name(pos))) -- cgit v1.1 From 5c581041cf97aa7980b442de81ddea8273d6dcde Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Jan 2011 22:30:02 -0200 Subject: perf evlist: Adopt the pollfd array Allocating just the space needed for nr_cpus * nr_threads * nr_evsels, not the MAX_NR_CPUS and counters. LKML-Reference: Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 252ace8..1614d89 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -72,9 +72,6 @@ static struct perf_evlist *evsel_list; static long samples = 0; static u64 bytes_written = 0; -static struct pollfd *event_array; - -static int nr_poll = 0; static int nr_cpu = 0; static int file_new = 1; @@ -432,9 +429,9 @@ try_again: exit(-1); } - event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index); - event_array[nr_poll].events = POLLIN; - nr_poll++; + evlist->pollfd[evlist->nr_fds].fd = FD(evsel, nr_cpu, thread_index); + evlist->pollfd[evlist->nr_fds].events = POLLIN; + evlist->nr_fds++; } if (filter != NULL) { @@ -793,7 +790,7 @@ static int __cmd_record(int argc, const char **argv) if (hits == samples) { if (done) break; - err = poll(event_array, nr_poll, -1); + err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); waking++; } @@ -948,9 +945,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (perf_header__push_event(pos->attr.config, event_name(pos))) goto out_free_fd; } - event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * - MAX_COUNTERS * threads->nr)); - if (!event_array) + + if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0) goto out_free_fd; if (user_interval != ULLONG_MAX) @@ -968,13 +964,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) } else { fprintf(stderr, "frequency and count are zero, aborting\n"); err = -EINVAL; - goto out_free_event_array; + goto out_free_fd; } err = __cmd_record(argc, argv); -out_free_event_array: - free(event_array); out_free_fd: thread_map__delete(threads); threads = NULL; -- cgit v1.1 From dd7927f4f8ee75b032ff15aeef4bda49719a443a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Jan 2011 14:28:51 -0200 Subject: perf record: Use perf_evsel__open Now its time to factor out the mmap handling bits into the perf_evsel class. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 233 +++++++++++++++++++++----------------------- 1 file changed, 113 insertions(+), 120 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 1614d89..ec43f2e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -72,8 +72,6 @@ static struct perf_evlist *evsel_list; static long samples = 0; static u64 bytes_written = 0; -static int nr_cpu = 0; - static int file_new = 1; static off_t post_processing_offset; @@ -208,8 +206,6 @@ static void sig_atexit(void) kill(getpid(), signr); } -static int group_fd; - static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) { struct perf_header_attr *h_attr; @@ -234,7 +230,6 @@ static void create_counter(struct perf_evlist *evlist, char *filter = evsel->filter; struct perf_event_attr *attr = &evsel->attr; struct perf_header_attr *h_attr; - int track = !evsel->idx; /* only the first counter needs these */ int thread_index; int ret; struct { @@ -243,19 +238,77 @@ static void create_counter(struct perf_evlist *evlist, u64 time_running; u64 id; } read_data; - /* - * Check if parse_single_tracepoint_event has already asked for - * PERF_SAMPLE_TIME. - * - * XXX this is kludgy but short term fix for problems introduced by - * eac23d1c that broke 'perf script' by having different sample_types - * when using multiple tracepoint events when we use a perf binary - * that tries to use sample_id_all on an older kernel. - * - * We need to move counter creation to perf_session, support - * different sample_types, etc. - */ - bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; + + for (thread_index = 0; thread_index < threads->nr; thread_index++) { + h_attr = get_header_attr(attr, evsel->idx); + if (h_attr == NULL) + die("nomem\n"); + + if (!file_new) { + if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { + fprintf(stderr, "incompatible append\n"); + exit(-1); + } + } + + if (read(FD(evsel, cpu, thread_index), &read_data, sizeof(read_data)) == -1) { + perror("Unable to read perf file descriptor"); + exit(-1); + } + + if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { + pr_warning("Not enough memory to add id\n"); + exit(-1); + } + + assert(FD(evsel, cpu, thread_index) >= 0); + fcntl(FD(evsel, cpu, thread_index), F_SETFL, O_NONBLOCK); + + if (evsel->idx || thread_index) { + struct perf_evsel *first; + first = list_entry(evlist->entries.next, struct perf_evsel, node); + ret = ioctl(FD(evsel, cpu, thread_index), + PERF_EVENT_IOC_SET_OUTPUT, + FD(first, cpu, 0)); + if (ret) { + error("failed to set output: %d (%s)\n", errno, + strerror(errno)); + exit(-1); + } + } else { + mmap_array[cpu].prev = 0; + mmap_array[cpu].mask = mmap_pages*page_size - 1; + mmap_array[cpu].base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, cpu, thread_index), 0); + if (mmap_array[cpu].base == MAP_FAILED) { + error("failed to mmap with %d (%s)\n", errno, strerror(errno)); + exit(-1); + } + + evlist->pollfd[evlist->nr_fds].fd = FD(evsel, cpu, thread_index); + evlist->pollfd[evlist->nr_fds].events = POLLIN; + evlist->nr_fds++; + } + + if (filter != NULL) { + ret = ioctl(FD(evsel, cpu, thread_index), + PERF_EVENT_IOC_SET_FILTER, filter); + if (ret) { + error("failed to set filter with %d (%s)\n", errno, + strerror(errno)); + exit(-1); + } + } + } + + if (!sample_type) + sample_type = attr->sample_type; +} + +static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) +{ + struct perf_event_attr *attr = &evsel->attr; + int track = !evsel->idx; /* only the first counter needs these */ attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | @@ -315,19 +368,39 @@ static void create_counter(struct perf_evlist *evlist, attr->mmap = track; attr->comm = track; - attr->inherit = !no_inherit; + if (target_pid == -1 && target_tid == -1 && !system_wide) { attr->disabled = 1; attr->enable_on_exec = 1; } -retry_sample_id: - attr->sample_id_all = sample_id_all_avail ? 1 : 0; +} - for (thread_index = 0; thread_index < threads->nr; thread_index++) { -try_again: - FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); +static void open_counters(struct perf_evlist *evlist) +{ + struct perf_evsel *pos; + int cpu; + + list_for_each_entry(pos, &evlist->entries, node) { + struct perf_event_attr *attr = &pos->attr; + /* + * Check if parse_single_tracepoint_event has already asked for + * PERF_SAMPLE_TIME. + * + * XXX this is kludgy but short term fix for problems introduced by + * eac23d1c that broke 'perf script' by having different sample_types + * when using multiple tracepoint events when we use a perf binary + * that tries to use sample_id_all on an older kernel. + * + * We need to move counter creation to perf_session, support + * different sample_types, etc. + */ + bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - if (FD(evsel, nr_cpu, thread_index) < 0) { + config_attr(pos, evlist); +retry_sample_id: + attr->sample_id_all = sample_id_all_avail ? 1 : 0; +try_again: + if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -364,7 +437,7 @@ try_again: } printf("\n"); error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", - FD(evsel, nr_cpu, thread_index), strerror(err)); + err, strerror(err)); #if defined(__i386__) || defined(__x86_64__) if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) @@ -375,90 +448,13 @@ try_again: #endif die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); - exit(-1); - } - - h_attr = get_header_attr(attr, evsel->idx); - if (h_attr == NULL) - die("nomem\n"); - - if (!file_new) { - if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { - fprintf(stderr, "incompatible append\n"); - exit(-1); - } - } - - if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { - perror("Unable to read perf file descriptor"); - exit(-1); - } - - if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { - pr_warning("Not enough memory to add id\n"); - exit(-1); - } - - 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(evsel, nr_cpu, thread_index); - - if (evsel->idx || thread_index) { - struct perf_evsel *first; - first = list_entry(evlist->entries.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].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(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); - } - - evlist->pollfd[evlist->nr_fds].fd = FD(evsel, nr_cpu, thread_index); - evlist->pollfd[evlist->nr_fds].events = POLLIN; - evlist->nr_fds++; - } - - if (filter != NULL) { - 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)); - exit(-1); - } } } - if (!sample_type) - sample_type = attr->sample_type; -} - -static void open_counters(struct perf_evlist *evlist, int cpu) -{ - struct perf_evsel *pos; - - group_fd = -1; - - list_for_each_entry(pos, &evlist->entries, node) - create_counter(evlist, pos, cpu); - - nr_cpu++; + for (cpu = 0; cpu < cpus->nr; ++cpu) { + list_for_each_entry(pos, &evlist->entries, node) + create_counter(evlist, pos, cpu); + } } static int process_buildids(void) @@ -533,7 +529,7 @@ static void mmap_read_all(void) { int i; - for (i = 0; i < nr_cpu; i++) { + for (i = 0; i < cpus->nr; i++) { if (mmap_array[i].base) mmap_read(&mmap_array[i]); } @@ -673,12 +669,7 @@ static int __cmd_record(int argc, const char **argv) close(child_ready_pipe[0]); } - if (!system_wide && no_inherit && !cpu_list) { - open_counters(evsel_list, -1); - } else { - for (i = 0; i < cpus->nr; i++) - open_counters(evsel_list, cpus->map[i]); - } + open_counters(evsel_list); perf_session__set_sample_type(session, sample_type); @@ -795,7 +786,7 @@ static int __cmd_record(int argc, const char **argv) } if (done) { - for (i = 0; i < nr_cpu; i++) { + for (i = 0; i < cpus->nr; i++) { struct perf_evsel *pos; list_for_each_entry(pos, &evsel_list->entries, node) { @@ -933,11 +924,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) usage_with_options(record_usage, record_options); } - cpus = cpu_map__new(cpu_list); - if (cpus == NULL) { - perror("failed to parse CPUs map"); - return -1; - } + if (target_tid != -1) + cpus = cpu_map__dummy_new(); + else + cpus = cpu_map__new(cpu_list); + + if (cpus == NULL) + usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) -- cgit v1.1 From 744bd8aa3c8b43447f689a27872fa95e700b8a4f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Jan 2011 17:07:28 -0200 Subject: perf record: Use struct perf_mmap and helpers Paving the way to using perf_evsel->mmap, do this to reduce the patch noise in the next ones. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ec43f2e..d89e2f1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -78,26 +78,9 @@ static off_t post_processing_offset; static struct perf_session *session; static const char *cpu_list; -struct mmap_data { - void *base; - unsigned int mask; - unsigned int prev; -}; - -static struct mmap_data mmap_array[MAX_NR_CPUS]; - -static unsigned long mmap_read_head(struct mmap_data *md) -{ - struct perf_event_mmap_page *pc = md->base; - long head; - - head = pc->data_head; - rmb(); - - return head; -} +static struct perf_mmap mmap_array[MAX_NR_CPUS]; -static void mmap_write_tail(struct mmap_data *md, unsigned long tail) +static void mmap_write_tail(struct perf_mmap *md, unsigned long tail) { struct perf_event_mmap_page *pc = md->base; @@ -136,9 +119,9 @@ static int process_synthesized_event(event_t *event, return 0; } -static void mmap_read(struct mmap_data *md) +static void mmap_read(struct perf_mmap *md) { - unsigned int head = mmap_read_head(md); + unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; unsigned long size; -- cgit v1.1 From 115d2d8963a426670ac3ce983fc4c4e001703943 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Jan 2011 17:11:53 -0200 Subject: perf record: Move perf_mmap__write_tail to perf.h Close to perf_mmap__read_head() and the perf_mmap struct definition. This is useful for any recorder, and we will need it in 'perf test'. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d89e2f1..109f3b2 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -80,17 +80,6 @@ static const char *cpu_list; static struct perf_mmap mmap_array[MAX_NR_CPUS]; -static void mmap_write_tail(struct perf_mmap *md, unsigned long tail) -{ - struct perf_event_mmap_page *pc = md->base; - - /* - * ensure all reads are done before we write the tail out. - */ - /* mb(); */ - pc->data_tail = tail; -} - static void advance_output(size_t size) { bytes_written += size; @@ -165,7 +154,7 @@ static void mmap_read(struct perf_mmap *md) write_output(buf, size); md->prev = old; - mmap_write_tail(md, old); + perf_mmap__write_tail(md, old); } static volatile int done = 0; -- cgit v1.1 From 0a27d7f9f417c0305f7efa70631764a53c7af219 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 14 Jan 2011 15:50:51 -0200 Subject: perf record: Use perf_evlist__mmap There is more stuff that can go to the perf_ev{sel,list} layer, like detecting if sample_id_all is available, etc, but lets try using this in 'perf test' first. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 59 +++++++++------------------------------------ 1 file changed, 11 insertions(+), 48 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 109f3b2..45a3689 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -30,6 +30,7 @@ #include #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) +#define SID(e, x, y) xyarray__entry(e->id, x, y) enum write_mode_t { WRITE_FORCE, @@ -78,8 +79,6 @@ static off_t post_processing_offset; static struct perf_session *session; static const char *cpu_list; -static struct perf_mmap mmap_array[MAX_NR_CPUS]; - static void advance_output(size_t size) { bytes_written += size; @@ -196,20 +195,14 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n return h_attr; } -static void create_counter(struct perf_evlist *evlist, - struct perf_evsel *evsel, int cpu) +static void create_counter(struct perf_evsel *evsel, int cpu) { char *filter = evsel->filter; struct perf_event_attr *attr = &evsel->attr; struct perf_header_attr *h_attr; + struct perf_sample_id *sid; int thread_index; int ret; - struct { - u64 count; - u64 time_enabled; - u64 time_running; - u64 id; - } read_data; for (thread_index = 0; thread_index < threads->nr; thread_index++) { h_attr = get_header_attr(attr, evsel->idx); @@ -223,45 +216,12 @@ static void create_counter(struct perf_evlist *evlist, } } - if (read(FD(evsel, cpu, thread_index), &read_data, sizeof(read_data)) == -1) { - perror("Unable to read perf file descriptor"); - exit(-1); - } - - if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { + sid = SID(evsel, cpu, thread_index); + if (perf_header_attr__add_id(h_attr, sid->id) < 0) { pr_warning("Not enough memory to add id\n"); exit(-1); } - assert(FD(evsel, cpu, thread_index) >= 0); - fcntl(FD(evsel, cpu, thread_index), F_SETFL, O_NONBLOCK); - - if (evsel->idx || thread_index) { - struct perf_evsel *first; - first = list_entry(evlist->entries.next, struct perf_evsel, node); - ret = ioctl(FD(evsel, cpu, thread_index), - PERF_EVENT_IOC_SET_OUTPUT, - FD(first, cpu, 0)); - if (ret) { - error("failed to set output: %d (%s)\n", errno, - strerror(errno)); - exit(-1); - } - } else { - mmap_array[cpu].prev = 0; - mmap_array[cpu].mask = mmap_pages*page_size - 1; - mmap_array[cpu].base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, cpu, thread_index), 0); - if (mmap_array[cpu].base == MAP_FAILED) { - error("failed to mmap with %d (%s)\n", errno, strerror(errno)); - exit(-1); - } - - evlist->pollfd[evlist->nr_fds].fd = FD(evsel, cpu, thread_index); - evlist->pollfd[evlist->nr_fds].events = POLLIN; - evlist->nr_fds++; - } - if (filter != NULL) { ret = ioctl(FD(evsel, cpu, thread_index), PERF_EVENT_IOC_SET_FILTER, filter); @@ -423,9 +383,12 @@ try_again: } } + if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, false) < 0) + die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + for (cpu = 0; cpu < cpus->nr; ++cpu) { list_for_each_entry(pos, &evlist->entries, node) - create_counter(evlist, pos, cpu); + create_counter(pos, cpu); } } @@ -502,8 +465,8 @@ static void mmap_read_all(void) int i; for (i = 0; i < cpus->nr; i++) { - if (mmap_array[i].base) - mmap_read(&mmap_array[i]); + if (evsel_list->mmap[i].base) + mmap_read(&evsel_list->mmap[i]); } if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) -- cgit v1.1 From d7065adb9b4f3384c2615f0a3dbdb6c3aae1eb18 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Sun, 16 Jan 2011 17:14:45 +0100 Subject: perf record: auto detect when stdout is a pipe This patch gives the ability to 'perf record' to detect when its stdout has been redirected to a pipe. There's now no more need to add '-o -' switch in this case. However '-o ' option has always precedence, that is if specified and stdout has been connected via a pipe then the output will go into the specified output. LKML-Reference: Signed-off-by: Franck Bui-Huu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 45a3689..1346d42 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -48,7 +48,7 @@ static unsigned int user_freq = UINT_MAX; static int freq = 1000; static int output; static int pipe_output = 0; -static const char *output_name = "perf.data"; +static const char *output_name = NULL; static int group = 0; static int realtime_prio = 0; static bool nodelay = false; @@ -497,18 +497,26 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } - if (!strcmp(output_name, "-")) - pipe_output = 1; - else if (!stat(output_name, &st) && st.st_size) { - if (write_mode == WRITE_FORCE) { - char oldname[PATH_MAX]; - snprintf(oldname, sizeof(oldname), "%s.old", - output_name); - unlink(oldname); - rename(output_name, oldname); + if (!output_name) { + if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) + pipe_output = 1; + else + output_name = "perf.data"; + } + if (output_name) { + if (!strcmp(output_name, "-")) + pipe_output = 1; + else if (!stat(output_name, &st) && st.st_size) { + if (write_mode == WRITE_FORCE) { + char oldname[PATH_MAX]; + snprintf(oldname, sizeof(oldname), "%s.old", + output_name); + unlink(oldname); + rename(output_name, oldname); + } + } else if (write_mode == WRITE_APPEND) { + write_mode = WRITE_FORCE; } - } else if (write_mode == WRITE_APPEND) { - write_mode = WRITE_FORCE; } flags = O_CREAT|O_RDWR; -- cgit v1.1 From fd78260b5376173faeb17127bd63b3c99a8e8bfb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Jan 2011 15:15:24 -0200 Subject: perf threads: Move thread_map to separate file To untangle it from struct thread handling, that is tied to symbols, etc. Right now in the python bindings I'm working on I need just a subset of the util/ files, untangling it allows me to do that. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 1346d42..d788630 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -24,6 +24,7 @@ #include "util/session.h" #include "util/symbol.h" #include "util/cpumap.h" +#include "util/thread_map.h" #include #include -- cgit v1.1 From dc82009aac6ee6e423b48de43a251745c62ab012 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 28 Jan 2011 14:49:19 -0200 Subject: perf record: No need to check for overwrites As we open the mmap with (PROT_READ | PROT_WRITE), signalling the kernel with perf_mmap__write_tail() when consuming data, so the kernel will not overwrite. Suggested-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d788630..caf9279 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -115,27 +115,11 @@ static void mmap_read(struct perf_mmap *md) unsigned char *data = md->base + page_size; unsigned long size; void *buf; - int diff; - /* - * If we're further behind than half the buffer, there's a chance - * the writer will bite our tail and mess up the samples under us. - * - * If we somehow ended up ahead of the head, we got messed up. - * - * In either case, truncate and restart at head. - */ - diff = head - old; - if (diff < 0) { - fprintf(stderr, "WARNING: failed to keep up with mmap data\n"); - /* - * head points to a known good entry, start there. - */ - old = head; - } + if (old == head) + return; - if (old != head) - samples++; + samples++; size = head - old; -- cgit v1.1 From 8d50e5b4171a69cf48ca94a1e7c14033d0b4771d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 29 Jan 2011 13:02:00 -0200 Subject: perf tools: Rename 'struct sample_data' to 'struct perf_sample' Making the namespace more uniform. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index caf9279..5d3e4b3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -101,7 +101,7 @@ static void write_output(void *buf, size_t size) } static int process_synthesized_event(event_t *event, - struct sample_data *sample __used, + struct perf_sample *sample __used, struct perf_session *self __used) { write_output(event, event->header.size); -- cgit v1.1 From 8115d60c323dd9931b95221c0a392aeddc1d6ef3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 29 Jan 2011 14:01:45 -0200 Subject: perf tools: Kill event_t typedef, use 'union perf_event' instead And move the event_t methods to the perf_event__ too. No code changes, just namespace consistency. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 56 ++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 5d3e4b3..edc3555 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -100,7 +100,7 @@ static void write_output(void *buf, size_t size) } } -static int process_synthesized_event(event_t *event, +static int process_synthesized_event(union perf_event *event, struct perf_sample *sample __used, struct perf_session *self __used) { @@ -404,7 +404,7 @@ static void atexit_header(void) } } -static void event__synthesize_guest_os(struct machine *machine, void *data) +static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; struct perf_session *psession = data; @@ -420,8 +420,8 @@ static void event__synthesize_guest_os(struct machine *machine, void *data) *method is used to avoid symbol missing when the first addr is *in module instead of in guest kernel. */ - err = event__synthesize_modules(process_synthesized_event, - psession, machine); + err = perf_event__synthesize_modules(process_synthesized_event, + psession, machine); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" " relocation symbol.\n", machine->pid); @@ -430,11 +430,12 @@ static void event__synthesize_guest_os(struct machine *machine, void *data) * We use _stext for guest kernel because guest kernel's /proc/kallsyms * have no _text sometimes. */ - err = event__synthesize_kernel_mmap(process_synthesized_event, - psession, machine, "_text"); + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + psession, machine, "_text"); if (err < 0) - err = event__synthesize_kernel_mmap(process_synthesized_event, - psession, machine, "_stext"); + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + psession, machine, + "_stext"); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" " relocation symbol.\n", machine->pid); @@ -617,16 +618,16 @@ static int __cmd_record(int argc, const char **argv) perf_session__set_sample_id_all(session, sample_id_all_avail); if (pipe_output) { - err = event__synthesize_attrs(&session->header, - process_synthesized_event, - session); + err = perf_event__synthesize_attrs(&session->header, + process_synthesized_event, + session); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); return err; } - err = event__synthesize_event_types(process_synthesized_event, - session); + err = perf_event__synthesize_event_types(process_synthesized_event, + session); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); return err; @@ -641,9 +642,9 @@ 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, evsel_list, - process_synthesized_event, - session); + err = perf_event__synthesize_tracing_data(output, evsel_list, + process_synthesized_event, + session); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); return err; @@ -658,31 +659,34 @@ static int __cmd_record(int argc, const char **argv) return -1; } - err = event__synthesize_kernel_mmap(process_synthesized_event, - session, machine, "_text"); + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + session, machine, "_text"); if (err < 0) - err = event__synthesize_kernel_mmap(process_synthesized_event, - session, machine, "_stext"); + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + session, machine, "_stext"); if (err < 0) pr_err("Couldn't record kernel reference relocation symbol\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/kallsyms permission or run as root.\n"); - err = event__synthesize_modules(process_synthesized_event, - session, machine); + err = perf_event__synthesize_modules(process_synthesized_event, + session, machine); if (err < 0) pr_err("Couldn't record kernel module information.\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/modules permission or run as root.\n"); if (perf_guest) - perf_session__process_machines(session, event__synthesize_guest_os); + perf_session__process_machines(session, + perf_event__synthesize_guest_os); if (!system_wide) - event__synthesize_thread(target_tid, process_synthesized_event, - session); + perf_event__synthesize_thread(target_tid, + process_synthesized_event, + session); else - event__synthesize_threads(process_synthesized_event, session); + perf_event__synthesize_threads(process_synthesized_event, + session); if (realtime_prio) { struct sched_param param; -- cgit v1.1 From 7e2ed097538c57ff5268e9a6bced7c0b885809c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 30 Jan 2011 11:59:43 -0200 Subject: perf evlist: Store pointer to the cpu and thread maps So that we don't have to pass it around to the several methods that needs it, simplifying usage. There is one case where we don't have the thread/cpu map in advance, which is in the parsing routines used by top, stat, record, that we have to wait till all options are parsed to know if a cpu or thread list was passed to then create those maps. For that case consolidate the cpu and thread map creation via perf_evlist__create_maps() out of the code in top and record, while also providing a perf_evlist__set_maps() for cases where multiple evlists share maps or for when maps that represent CPU sockets, for instance, get crafted out of topology information or subsets of threads in a particular application are to be monitored, providing more granularity in specifying which cpus and threads to monitor. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index edc3555..07f8d6d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -42,7 +42,6 @@ static u64 user_interval = ULLONG_MAX; static u64 default_interval = 0; static u64 sample_type; -static struct cpu_map *cpus; static unsigned int page_size; static unsigned int mmap_pages = 128; static unsigned int user_freq = UINT_MAX; @@ -58,7 +57,6 @@ 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 struct thread_map *threads; static pid_t child_pid = -1; static bool no_inherit = false; static enum write_mode_t write_mode = WRITE_FORCE; @@ -189,7 +187,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu) int thread_index; int ret; - for (thread_index = 0; thread_index < threads->nr; thread_index++) { + for (thread_index = 0; thread_index < evsel_list->threads->nr; thread_index++) { h_attr = get_header_attr(attr, evsel->idx); if (h_attr == NULL) die("nomem\n"); @@ -317,7 +315,8 @@ static void open_counters(struct perf_evlist *evlist) retry_sample_id: attr->sample_id_all = sample_id_all_avail ? 1 : 0; try_again: - if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) { + if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, + !no_inherit) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -368,10 +367,10 @@ try_again: } } - if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, false) < 0) + if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); - for (cpu = 0; cpu < cpus->nr; ++cpu) { + for (cpu = 0; cpu < evsel_list->cpus->nr; ++cpu) { list_for_each_entry(pos, &evlist->entries, node) create_counter(pos, cpu); } @@ -450,7 +449,7 @@ static void mmap_read_all(void) { int i; - for (i = 0; i < cpus->nr; i++) { + for (i = 0; i < evsel_list->cpus->nr; i++) { if (evsel_list->mmap[i].base) mmap_read(&evsel_list->mmap[i]); } @@ -584,7 +583,7 @@ static int __cmd_record(int argc, const char **argv) } if (!system_wide && target_tid == -1 && target_pid == -1) - threads->map[0] = child_pid; + evsel_list->threads->map[0] = child_pid; close(child_ready_pipe[1]); close(go_pipe[0]); @@ -718,12 +717,12 @@ static int __cmd_record(int argc, const char **argv) } if (done) { - for (i = 0; i < cpus->nr; i++) { + for (i = 0; i < evsel_list->cpus->nr; i++) { struct perf_evsel *pos; list_for_each_entry(pos, &evsel_list->entries, node) { for (thread = 0; - thread < threads->nr; + thread < evsel_list->threads->nr; thread++) ioctl(FD(pos, i, thread), PERF_EVENT_IOC_DISABLE); @@ -816,7 +815,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) int err = -ENOMEM; struct perf_evsel *pos; - evsel_list = perf_evlist__new(); + evsel_list = perf_evlist__new(NULL, NULL); if (evsel_list == NULL) return -ENOMEM; @@ -850,28 +849,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (target_pid != -1) target_tid = target_pid; - 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); - } - - if (target_tid != -1) - cpus = cpu_map__dummy_new(); - else - cpus = cpu_map__new(cpu_list); - - if (cpus == NULL) + if (perf_evlist__create_maps(evsel_list, target_pid, + target_tid, cpu_list) < 0) usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) + if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, + evsel_list->threads->nr) < 0) goto out_free_fd; if (perf_header__push_event(pos->attr.config, event_name(pos))) goto out_free_fd; } - if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0) + if (perf_evlist__alloc_pollfd(evsel_list) < 0) goto out_free_fd; if (user_interval != ULLONG_MAX) @@ -893,10 +883,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) } err = __cmd_record(argc, argv); - out_free_fd: - thread_map__delete(threads); - threads = NULL; + perf_evlist__delete_maps(evsel_list); out_symbol_exit: symbol__exit(); return err; -- cgit v1.1 From 023695d96ee06f36cf5014e286edcd623e9fb847 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 14 Feb 2011 11:20:01 +0200 Subject: perf tool: Add cgroup support This patch adds the ability to filter monitoring based on container groups (cgroups) for both perf stat and perf record. It is possible to monitor multiple cgroup in parallel. There is one cgroup per event. The cgroups to monitor are passed via a new -G option followed by a comma separated list of cgroup names. The cgroup filesystem has to be mounted. Given a cgroup name, the perf tool finds the corresponding directory in the cgroup filesystem and opens it. It then passes that file descriptor to the kernel. Example: $ perf stat -B -a -e cycles:u,cycles:u,cycles:u -G test1,,test2 -- sleep 1 Performance counter stats for 'sleep 1': 2,368,667,414 cycles test1 2,369,661,459 cycles cycles test2 1.001856890 seconds time elapsed Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra LKML-Reference: <4d590290.825bdf0a.7d0a.4890@mx.google.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 12e0e41..a4aaadc 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -807,6 +807,9 @@ const struct option record_options[] = { "do not update the buildid cache"), OPT_BOOLEAN('B', "no-buildid", &no_buildid, "do not collect buildids in perf.data"), + OPT_CALLBACK('G', "cgroup", &evsel_list, "name", + "monitor event in cgroup name only", + parse_cgroups), OPT_END() }; @@ -835,6 +838,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) write_mode = WRITE_FORCE; } + if (nr_cgroups && !system_wide) { + fprintf(stderr, "cgroup monitoring only available in" + " system-wide mode\n"); + usage_with_options(record_usage, record_options); + } + symbol__init(); if (no_buildid_cache || no_buildid) -- cgit v1.1 From 712a4b6049724278121d56aba683151d86c8c35a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Feb 2011 12:18:42 -0200 Subject: perf record: Delay setting the header writing atexit call While testing the --filter option I noticed that we were writing lots of unneeded stuff to the perf.data header when the filter ioctl fails, so move the atexit(atexit_header) call to after we create the counters successfully. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a4aaadc..db4cd1e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -538,11 +538,6 @@ static int __cmd_record(int argc, const char **argv) if (have_tracepoints(&evsel_list->entries)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); - /* - * perf_session__delete(session) will be called at atexit_header() - */ - atexit(atexit_header); - if (forks) { child_pid = fork(); if (child_pid < 0) { @@ -601,6 +596,11 @@ static int __cmd_record(int argc, const char **argv) perf_session__set_sample_type(session, sample_type); + /* + * perf_session__delete(session) will be called at atexit_header() + */ + atexit(atexit_header); + if (pipe_output) { err = perf_header__write_pipe(output); if (err < 0) -- cgit v1.1 From 0a10247914a5cad3caf7ef8a255c54c4d3ed2062 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 26 Feb 2011 04:51:54 +0100 Subject: perf: Set filters before mmaping events We currently set the filters after we mmap the events, this is a race that let undesired events record themselves in the buffer before we had the time to set the filters. So set the filters before they can be recorded. That also librarizes the filters setting so that filtering can be done more easily from other tools than perf record later. Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Cc: Arnaldo Carvalho de Melo Cc: Steven Rostedt --- tools/perf/builtin-record.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index db4cd1e..d40a81e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -180,12 +180,10 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n static void create_counter(struct perf_evsel *evsel, int cpu) { - char *filter = evsel->filter; struct perf_event_attr *attr = &evsel->attr; struct perf_header_attr *h_attr; struct perf_sample_id *sid; int thread_index; - int ret; for (thread_index = 0; thread_index < evsel_list->threads->nr; thread_index++) { h_attr = get_header_attr(attr, evsel->idx); @@ -204,16 +202,6 @@ static void create_counter(struct perf_evsel *evsel, int cpu) pr_warning("Not enough memory to add id\n"); exit(-1); } - - if (filter != NULL) { - ret = ioctl(FD(evsel, cpu, thread_index), - PERF_EVENT_IOC_SET_FILTER, filter); - if (ret) { - error("failed to set filter with %d (%s)\n", errno, - strerror(errno)); - exit(-1); - } - } } if (!sample_type) @@ -367,6 +355,12 @@ try_again: } } + if (perf_evlist__set_filters(evlist)) { + error("failed to set filter with %d (%s)\n", errno, + strerror(errno)); + exit(-1); + } + if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); -- cgit v1.1 From a91e5431d54f5359fccb5ec2512f252eb217707e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 10 Mar 2011 11:15:54 -0300 Subject: perf session: Use evlist/evsel for managing perf.data attributes So that we can reuse things like the id to attr lookup routine (perf_evlist__id2evsel) that uses a hash table instead of the linear lookup done in the older perf_header_attr routines, etc. Also to make evsels/evlist more pervasive an API, simplyfing using the emerging perf lib. cc: Arun Sharma Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 101 +++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 66 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d40a81e..6febcc1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -31,7 +31,6 @@ #include #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) -#define SID(e, x, y) xyarray__entry(e->id, x, y) enum write_mode_t { WRITE_FORCE, @@ -40,7 +39,6 @@ enum write_mode_t { static u64 user_interval = ULLONG_MAX; static u64 default_interval = 0; -static u64 sample_type; static unsigned int page_size; static unsigned int mmap_pages = 128; @@ -160,54 +158,6 @@ static void sig_atexit(void) kill(getpid(), signr); } -static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) -{ - struct perf_header_attr *h_attr; - - if (nr < session->header.attrs) { - h_attr = session->header.attr[nr]; - } else { - h_attr = perf_header_attr__new(a); - if (h_attr != NULL) - if (perf_header__add_attr(&session->header, h_attr) < 0) { - perf_header_attr__delete(h_attr); - h_attr = NULL; - } - } - - return h_attr; -} - -static void create_counter(struct perf_evsel *evsel, int cpu) -{ - struct perf_event_attr *attr = &evsel->attr; - struct perf_header_attr *h_attr; - struct perf_sample_id *sid; - int thread_index; - - for (thread_index = 0; thread_index < evsel_list->threads->nr; thread_index++) { - h_attr = get_header_attr(attr, evsel->idx); - if (h_attr == NULL) - die("nomem\n"); - - if (!file_new) { - if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { - fprintf(stderr, "incompatible append\n"); - exit(-1); - } - } - - sid = SID(evsel, cpu, thread_index); - if (perf_header_attr__add_id(h_attr, sid->id) < 0) { - pr_warning("Not enough memory to add id\n"); - exit(-1); - } - } - - if (!sample_type) - sample_type = attr->sample_type; -} - static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) { struct perf_event_attr *attr = &evsel->attr; @@ -278,10 +228,28 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) } } +static bool perf_evlist__equal(struct perf_evlist *evlist, + struct perf_evlist *other) +{ + struct perf_evsel *pos, *pair; + + if (evlist->nr_entries != other->nr_entries) + return false; + + pair = list_entry(other->entries.next, struct perf_evsel, node); + + list_for_each_entry(pos, &evlist->entries, node) { + if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0)) + return false; + pair = list_entry(pair->node.next, struct perf_evsel, node); + } + + return true; +} + static void open_counters(struct perf_evlist *evlist) { struct perf_evsel *pos; - int cpu; list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; @@ -364,10 +332,16 @@ try_again: if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); - for (cpu = 0; cpu < evsel_list->cpus->nr; ++cpu) { - list_for_each_entry(pos, &evlist->entries, node) - create_counter(pos, cpu); - } + if (file_new) + session->evlist = evlist; + else { + if (!perf_evlist__equal(session->evlist, evlist)) { + fprintf(stderr, "incompatible append\n"); + exit(-1); + } + } + + perf_session__update_sample_type(session); } static int process_buildids(void) @@ -390,7 +364,7 @@ static void atexit_header(void) if (!no_buildid) process_buildids(); - perf_header__write(&session->header, evsel_list, output, true); + perf_session__write_header(session, evsel_list, output, true); perf_session__delete(session); perf_evlist__delete(evsel_list); symbol__exit(); @@ -524,7 +498,7 @@ static int __cmd_record(int argc, const char **argv) perf_header__set_feat(&session->header, HEADER_BUILD_ID); if (!file_new) { - err = perf_header__read(session, output); + err = perf_session__read_header(session, output); if (err < 0) goto out_delete_session; } @@ -588,8 +562,6 @@ static int __cmd_record(int argc, const char **argv) open_counters(evsel_list); - perf_session__set_sample_type(session, sample_type); - /* * perf_session__delete(session) will be called at atexit_header() */ @@ -600,20 +572,17 @@ static int __cmd_record(int argc, const char **argv) if (err < 0) return err; } else if (file_new) { - err = perf_header__write(&session->header, evsel_list, - output, false); + err = perf_session__write_header(session, evsel_list, + output, false); if (err < 0) return err; } post_processing_offset = lseek(output, 0, SEEK_CUR); - perf_session__set_sample_id_all(session, sample_id_all_avail); - if (pipe_output) { - err = perf_event__synthesize_attrs(&session->header, - process_synthesized_event, - session); + err = perf_session__synthesize_attrs(session, + process_synthesized_event); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); return err; -- cgit v1.1