perf record: Use perf_evsel__open
Now its time to factor out the mmap handling bits into the perf_evsel class. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
72cb7013e0
commit
dd7927f4f8
|
@ -72,8 +72,6 @@ static struct perf_evlist *evsel_list;
|
||||||
static long samples = 0;
|
static long samples = 0;
|
||||||
static u64 bytes_written = 0;
|
static u64 bytes_written = 0;
|
||||||
|
|
||||||
static int nr_cpu = 0;
|
|
||||||
|
|
||||||
static int file_new = 1;
|
static int file_new = 1;
|
||||||
static off_t post_processing_offset;
|
static off_t post_processing_offset;
|
||||||
|
|
||||||
|
@ -208,8 +206,6 @@ static void sig_atexit(void)
|
||||||
kill(getpid(), signr);
|
kill(getpid(), signr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int group_fd;
|
|
||||||
|
|
||||||
static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
|
static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
|
||||||
{
|
{
|
||||||
struct perf_header_attr *h_attr;
|
struct perf_header_attr *h_attr;
|
||||||
|
@ -234,7 +230,6 @@ static void create_counter(struct perf_evlist *evlist,
|
||||||
char *filter = evsel->filter;
|
char *filter = evsel->filter;
|
||||||
struct perf_event_attr *attr = &evsel->attr;
|
struct perf_event_attr *attr = &evsel->attr;
|
||||||
struct perf_header_attr *h_attr;
|
struct perf_header_attr *h_attr;
|
||||||
int track = !evsel->idx; /* only the first counter needs these */
|
|
||||||
int thread_index;
|
int thread_index;
|
||||||
int ret;
|
int ret;
|
||||||
struct {
|
struct {
|
||||||
|
@ -243,19 +238,77 @@ static void create_counter(struct perf_evlist *evlist,
|
||||||
u64 time_running;
|
u64 time_running;
|
||||||
u64 id;
|
u64 id;
|
||||||
} read_data;
|
} read_data;
|
||||||
/*
|
|
||||||
* Check if parse_single_tracepoint_event has already asked for
|
for (thread_index = 0; thread_index < threads->nr; thread_index++) {
|
||||||
* PERF_SAMPLE_TIME.
|
h_attr = get_header_attr(attr, evsel->idx);
|
||||||
*
|
if (h_attr == NULL)
|
||||||
* XXX this is kludgy but short term fix for problems introduced by
|
die("nomem\n");
|
||||||
* eac23d1c that broke 'perf script' by having different sample_types
|
|
||||||
* when using multiple tracepoint events when we use a perf binary
|
if (!file_new) {
|
||||||
* that tries to use sample_id_all on an older kernel.
|
if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
|
||||||
*
|
fprintf(stderr, "incompatible append\n");
|
||||||
* We need to move counter creation to perf_session, support
|
exit(-1);
|
||||||
* different sample_types, etc.
|
}
|
||||||
*/
|
}
|
||||||
bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
|
|
||||||
|
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 |
|
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
|
||||||
PERF_FORMAT_TOTAL_TIME_RUNNING |
|
PERF_FORMAT_TOTAL_TIME_RUNNING |
|
||||||
|
@ -315,19 +368,39 @@ static void create_counter(struct perf_evlist *evlist,
|
||||||
|
|
||||||
attr->mmap = track;
|
attr->mmap = track;
|
||||||
attr->comm = track;
|
attr->comm = track;
|
||||||
attr->inherit = !no_inherit;
|
|
||||||
if (target_pid == -1 && target_tid == -1 && !system_wide) {
|
if (target_pid == -1 && target_tid == -1 && !system_wide) {
|
||||||
attr->disabled = 1;
|
attr->disabled = 1;
|
||||||
attr->enable_on_exec = 1;
|
attr->enable_on_exec = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
config_attr(pos, evlist);
|
||||||
retry_sample_id:
|
retry_sample_id:
|
||||||
attr->sample_id_all = sample_id_all_avail ? 1 : 0;
|
attr->sample_id_all = sample_id_all_avail ? 1 : 0;
|
||||||
|
|
||||||
for (thread_index = 0; thread_index < threads->nr; thread_index++) {
|
|
||||||
try_again:
|
try_again:
|
||||||
FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);
|
if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) {
|
||||||
|
|
||||||
if (FD(evsel, nr_cpu, thread_index) < 0) {
|
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
if (err == EPERM || err == EACCES)
|
if (err == EPERM || err == EACCES)
|
||||||
|
@ -364,7 +437,7 @@ try_again:
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\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 defined(__i386__) || defined(__x86_64__)
|
||||||
if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
|
if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
|
||||||
|
@ -375,90 +448,13 @@ try_again:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
|
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) {
|
for (cpu = 0; cpu < cpus->nr; ++cpu) {
|
||||||
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)
|
list_for_each_entry(pos, &evlist->entries, node)
|
||||||
create_counter(evlist, pos, cpu);
|
create_counter(evlist, pos, cpu);
|
||||||
|
}
|
||||||
nr_cpu++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_buildids(void)
|
static int process_buildids(void)
|
||||||
|
@ -533,7 +529,7 @@ static void mmap_read_all(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nr_cpu; i++) {
|
for (i = 0; i < cpus->nr; i++) {
|
||||||
if (mmap_array[i].base)
|
if (mmap_array[i].base)
|
||||||
mmap_read(&mmap_array[i]);
|
mmap_read(&mmap_array[i]);
|
||||||
}
|
}
|
||||||
|
@ -673,12 +669,7 @@ static int __cmd_record(int argc, const char **argv)
|
||||||
close(child_ready_pipe[0]);
|
close(child_ready_pipe[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!system_wide && no_inherit && !cpu_list) {
|
open_counters(evsel_list);
|
||||||
open_counters(evsel_list, -1);
|
|
||||||
} else {
|
|
||||||
for (i = 0; i < cpus->nr; i++)
|
|
||||||
open_counters(evsel_list, cpus->map[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
perf_session__set_sample_type(session, sample_type);
|
perf_session__set_sample_type(session, sample_type);
|
||||||
|
|
||||||
|
@ -795,7 +786,7 @@ static int __cmd_record(int argc, const char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
for (i = 0; i < nr_cpu; i++) {
|
for (i = 0; i < cpus->nr; i++) {
|
||||||
struct perf_evsel *pos;
|
struct perf_evsel *pos;
|
||||||
|
|
||||||
list_for_each_entry(pos, &evsel_list->entries, node) {
|
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);
|
usage_with_options(record_usage, record_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (target_tid != -1)
|
||||||
|
cpus = cpu_map__dummy_new();
|
||||||
|
else
|
||||||
cpus = cpu_map__new(cpu_list);
|
cpus = cpu_map__new(cpu_list);
|
||||||
if (cpus == NULL) {
|
|
||||||
perror("failed to parse CPUs map");
|
if (cpus == NULL)
|
||||||
return -1;
|
usage_with_options(record_usage, record_options);
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(pos, &evsel_list->entries, node) {
|
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, cpus->nr, threads->nr) < 0)
|
||||||
|
|
Loading…
Reference in New Issue