summaryrefslogtreecommitdiff
path: root/tools/perf/util/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r--tools/perf/util/session.c278
1 files changed, 146 insertions, 132 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index f36d24a..568b750 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,34 +16,73 @@
#include "perf_regs.h"
#include "vdso.h"
-static int perf_session__open(struct perf_session *session)
+static int perf_session__open(struct perf_session *self, bool force)
{
- struct perf_data_file *file = session->file;
+ struct stat input_stat;
- if (perf_session__read_header(session) < 0) {
- pr_err("incompatible file format (rerun with -v to learn more)");
- return -1;
- }
+ if (!strcmp(self->filename, "-")) {
+ self->fd_pipe = true;
+ self->fd = STDIN_FILENO;
+
+ if (perf_session__read_header(self) < 0)
+ pr_err("incompatible file format (rerun with -v to learn more)");
- if (perf_data_file__is_pipe(file))
return 0;
+ }
+
+ self->fd = open(self->filename, O_RDONLY);
+ if (self->fd < 0) {
+ int err = errno;
+
+ pr_err("failed to open %s: %s", self->filename, strerror(err));
+ if (err == ENOENT && !strcmp(self->filename, "perf.data"))
+ pr_err(" (try 'perf record' first)");
+ pr_err("\n");
+ return -errno;
+ }
+
+ if (fstat(self->fd, &input_stat) < 0)
+ goto out_close;
+
+ if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
+ pr_err("file %s not owned by current user or root\n",
+ self->filename);
+ goto out_close;
+ }
+
+ if (!input_stat.st_size) {
+ pr_info("zero-sized file (%s), nothing to do!\n",
+ self->filename);
+ goto out_close;
+ }
- if (!perf_evlist__valid_sample_type(session->evlist)) {
+ if (perf_session__read_header(self) < 0) {
+ pr_err("incompatible file format (rerun with -v to learn more)");
+ goto out_close;
+ }
+
+ if (!perf_evlist__valid_sample_type(self->evlist)) {
pr_err("non matching sample_type");
- return -1;
+ goto out_close;
}
- if (!perf_evlist__valid_sample_id_all(session->evlist)) {
+ if (!perf_evlist__valid_sample_id_all(self->evlist)) {
pr_err("non matching sample_id_all");
- return -1;
+ goto out_close;
}
- if (!perf_evlist__valid_read_format(session->evlist)) {
+ if (!perf_evlist__valid_read_format(self->evlist)) {
pr_err("non matching read_format");
- return -1;
+ goto out_close;
}
+ self->size = input_stat.st_size;
return 0;
+
+out_close:
+ close(self->fd);
+ self->fd = -1;
+ return -1;
}
void perf_session__set_id_hdr_size(struct perf_session *session)
@@ -53,70 +92,71 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
machines__set_id_hdr_size(&session->machines, id_hdr_size);
}
-int perf_session__create_kernel_maps(struct perf_session *session)
+int perf_session__create_kernel_maps(struct perf_session *self)
{
- int ret = machine__create_kernel_maps(&session->machines.host);
+ int ret = machine__create_kernel_maps(&self->machines.host);
if (ret >= 0)
- ret = machines__create_guest_kernel_maps(&session->machines);
+ ret = machines__create_guest_kernel_maps(&self->machines);
return ret;
}
-static void perf_session__destroy_kernel_maps(struct perf_session *session)
+static void perf_session__destroy_kernel_maps(struct perf_session *self)
{
- machines__destroy_kernel_maps(&session->machines);
+ machines__destroy_kernel_maps(&self->machines);
}
-struct perf_session *perf_session__new(struct perf_data_file *file,
- bool repipe, struct perf_tool *tool)
+struct perf_session *perf_session__new(const char *filename, int mode,
+ bool force, bool repipe,
+ struct perf_tool *tool)
{
- struct perf_session *session = zalloc(sizeof(*session));
-
- if (!session)
- goto out;
-
- session->repipe = repipe;
- INIT_LIST_HEAD(&session->ordered_samples.samples);
- INIT_LIST_HEAD(&session->ordered_samples.sample_cache);
- INIT_LIST_HEAD(&session->ordered_samples.to_free);
- machines__init(&session->machines);
+ struct perf_session *self;
+ struct stat st;
+ size_t len;
- if (file) {
- if (perf_data_file__open(file))
- goto out_delete;
+ if (!filename || !strlen(filename)) {
+ if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
+ filename = "-";
+ else
+ filename = "perf.data";
+ }
- session->file = file;
+ len = strlen(filename);
+ self = zalloc(sizeof(*self) + len);
- if (perf_data_file__is_read(file)) {
- if (perf_session__open(session) < 0)
- goto out_close;
+ if (self == NULL)
+ goto out;
- perf_session__set_id_hdr_size(session);
- }
- }
+ memcpy(self->filename, filename, len);
+ self->repipe = repipe;
+ INIT_LIST_HEAD(&self->ordered_samples.samples);
+ INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
+ INIT_LIST_HEAD(&self->ordered_samples.to_free);
+ machines__init(&self->machines);
- if (!file || perf_data_file__is_write(file)) {
+ if (mode == O_RDONLY) {
+ if (perf_session__open(self, force) < 0)
+ goto out_delete;
+ perf_session__set_id_hdr_size(self);
+ } else if (mode == O_WRONLY) {
/*
* In O_RDONLY mode this will be performed when reading the
* kernel MMAP event, in perf_event__process_mmap().
*/
- if (perf_session__create_kernel_maps(session) < 0)
+ if (perf_session__create_kernel_maps(self) < 0)
goto out_delete;
}
if (tool && tool->ordering_requires_timestamps &&
- tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) {
+ tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) {
dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
tool->ordered_samples = false;
}
- return session;
-
- out_close:
- perf_data_file__close(file);
- out_delete:
- perf_session__delete(session);
- out:
+out:
+ return self;
+out_delete:
+ perf_session__delete(self);
return NULL;
}
@@ -146,16 +186,15 @@ static void perf_session_env__delete(struct perf_session_env *env)
free(env->pmu_mappings);
}
-void perf_session__delete(struct perf_session *session)
+void perf_session__delete(struct perf_session *self)
{
- perf_session__destroy_kernel_maps(session);
- perf_session__delete_dead_threads(session);
- perf_session__delete_threads(session);
- perf_session_env__delete(&session->header.env);
- machines__exit(&session->machines);
- if (session->file)
- perf_data_file__close(session->file);
- free(session);
+ perf_session__destroy_kernel_maps(self);
+ perf_session__delete_dead_threads(self);
+ perf_session__delete_threads(self);
+ perf_session_env__delete(&self->header.env);
+ machines__exit(&self->machines);
+ close(self->fd);
+ free(self);
vdso__exit();
}
@@ -358,17 +397,6 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
swap_sample_id_all(event, &event->read + 1);
}
-static void perf_event__throttle_swap(union perf_event *event,
- bool sample_id_all)
-{
- event->throttle.time = bswap_64(event->throttle.time);
- event->throttle.id = bswap_64(event->throttle.id);
- event->throttle.stream_id = bswap_64(event->throttle.stream_id);
-
- if (sample_id_all)
- swap_sample_id_all(event, &event->throttle + 1);
-}
-
static u8 revbyte(u8 b)
{
int rev = (b >> 4) | ((b & 0xf) << 4);
@@ -414,9 +442,6 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
attr->bp_type = bswap_32(attr->bp_type);
attr->bp_addr = bswap_64(attr->bp_addr);
attr->bp_len = bswap_64(attr->bp_len);
- attr->branch_sample_type = bswap_64(attr->branch_sample_type);
- attr->sample_regs_user = bswap_64(attr->sample_regs_user);
- attr->sample_stack_user = bswap_32(attr->sample_stack_user);
swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
}
@@ -457,8 +482,6 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_EXIT] = perf_event__task_swap,
[PERF_RECORD_LOST] = perf_event__all64_swap,
[PERF_RECORD_READ] = perf_event__read_swap,
- [PERF_RECORD_THROTTLE] = perf_event__throttle_swap,
- [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap,
[PERF_RECORD_SAMPLE] = perf_event__all64_swap,
[PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
[PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
@@ -502,16 +525,13 @@ static int flush_sample_queue(struct perf_session *s,
struct perf_sample sample;
u64 limit = os->next_flush;
u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
+ unsigned idx = 0, progress_next = os->nr_samples / 16;
bool show_progress = limit == ULLONG_MAX;
- struct ui_progress prog;
int ret;
if (!tool->ordered_samples || !limit)
return 0;
- if (show_progress)
- ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
-
list_for_each_entry_safe(iter, tmp, head, list) {
if (session_done())
return 0;
@@ -532,9 +552,11 @@ static int flush_sample_queue(struct perf_session *s,
os->last_flush = iter->timestamp;
list_del(&iter->list);
list_add(&iter->list, &os->sample_cache);
-
- if (show_progress)
- ui_progress__update(&prog, 1);
+ if (show_progress && (++idx >= progress_next)) {
+ progress_next += os->nr_samples / 16;
+ ui_progress__update(idx, os->nr_samples,
+ "Processing time ordered events...");
+ }
}
if (list_empty(head)) {
@@ -838,9 +860,6 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
if (sample_type & PERF_SAMPLE_DATA_SRC)
printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
- if (sample_type & PERF_SAMPLE_TRANSACTION)
- printf("... transaction: %" PRIx64 "\n", sample->transaction);
-
if (sample_type & PERF_SAMPLE_READ)
sample_read__printf(sample, evsel->attr.read_format);
}
@@ -1012,7 +1031,6 @@ static int perf_session_deliver_event(struct perf_session *session,
static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
struct perf_tool *tool, u64 file_offset)
{
- int fd = perf_data_file__fd(session->file);
int err;
dump_event(session, event, file_offset, NULL);
@@ -1026,7 +1044,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
return err;
case PERF_RECORD_HEADER_TRACING_DATA:
/* setup for reading amidst mmap */
- lseek(fd, file_offset, SEEK_SET);
+ lseek(session->fd, file_offset, SEEK_SET);
return tool->tracing_data(tool, event, session);
case PERF_RECORD_HEADER_BUILD_ID:
return tool->build_id(tool, event, session);
@@ -1083,11 +1101,11 @@ static int perf_session__process_event(struct perf_session *session,
file_offset);
}
-void perf_event_header__bswap(struct perf_event_header *hdr)
+void perf_event_header__bswap(struct perf_event_header *self)
{
- hdr->type = bswap_32(hdr->type);
- hdr->misc = bswap_16(hdr->misc);
- hdr->size = bswap_16(hdr->size);
+ self->type = bswap_32(self->type);
+ self->misc = bswap_16(self->misc);
+ self->size = bswap_16(self->size);
}
struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
@@ -1095,11 +1113,11 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
return machine__findnew_thread(&session->machines.host, 0, pid);
}
-static struct thread *perf_session__register_idle_thread(struct perf_session *session)
+static struct thread *perf_session__register_idle_thread(struct perf_session *self)
{
- struct thread *thread = perf_session__findnew(session, 0);
+ struct thread *thread = perf_session__findnew(self, 0);
- if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
+ if (thread == NULL || thread__set_comm(thread, "swapper")) {
pr_err("problem inserting idle task.\n");
thread = NULL;
}
@@ -1149,10 +1167,9 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
volatile int session_done;
-static int __perf_session__process_pipe_events(struct perf_session *session,
+static int __perf_session__process_pipe_events(struct perf_session *self,
struct perf_tool *tool)
{
- int fd = perf_data_file__fd(session->file);
union perf_event *event;
uint32_t size, cur_size = 0;
void *buf = NULL;
@@ -1171,7 +1188,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
return -errno;
more:
event = buf;
- err = readn(fd, event, sizeof(struct perf_event_header));
+ err = readn(self->fd, event, sizeof(struct perf_event_header));
if (err <= 0) {
if (err == 0)
goto done;
@@ -1180,7 +1197,7 @@ more:
goto out_err;
}
- if (session->header.needs_swap)
+ if (self->header.needs_swap)
perf_event_header__bswap(&event->header);
size = event->header.size;
@@ -1203,7 +1220,7 @@ more:
p += sizeof(struct perf_event_header);
if (size - sizeof(struct perf_event_header)) {
- err = readn(fd, p, size - sizeof(struct perf_event_header));
+ err = readn(self->fd, p, size - sizeof(struct perf_event_header));
if (err <= 0) {
if (err == 0) {
pr_err("unexpected end of event stream\n");
@@ -1215,7 +1232,7 @@ more:
}
}
- if ((skip = perf_session__process_event(session, event, tool, head)) < 0) {
+ if ((skip = perf_session__process_event(self, event, tool, head)) < 0) {
pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
head, event->header.size, event->header.type);
err = -EINVAL;
@@ -1230,13 +1247,11 @@ more:
if (!session_done())
goto more;
done:
- /* do the final flush for ordered samples */
- session->ordered_samples.next_flush = ULLONG_MAX;
- err = flush_sample_queue(session, tool);
+ err = 0;
out_err:
free(buf);
- perf_session__warn_about_errors(session, tool);
- perf_session_free_sample_buffers(session);
+ perf_session__warn_about_errors(self, tool);
+ perf_session_free_sample_buffers(self);
return err;
}
@@ -1284,14 +1299,12 @@ int __perf_session__process_events(struct perf_session *session,
u64 data_offset, u64 data_size,
u64 file_size, struct perf_tool *tool)
{
- int fd = perf_data_file__fd(session->file);
- u64 head, page_offset, file_offset, file_pos;
+ u64 head, page_offset, file_offset, file_pos, progress_next;
int err, mmap_prot, mmap_flags, map_idx = 0;
size_t mmap_size;
char *buf, *mmaps[NUM_MMAPS];
union perf_event *event;
uint32_t size;
- struct ui_progress prog;
perf_tool__fill_defaults(tool);
@@ -1302,7 +1315,7 @@ int __perf_session__process_events(struct perf_session *session,
if (data_size && (data_offset + data_size < file_size))
file_size = data_offset + data_size;
- ui_progress__init(&prog, file_size, "Processing events...");
+ progress_next = file_size / 16;
mmap_size = MMAP_SIZE;
if (mmap_size > file_size)
@@ -1318,7 +1331,7 @@ int __perf_session__process_events(struct perf_session *session,
mmap_flags = MAP_PRIVATE;
}
remap:
- buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd,
+ buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
file_offset);
if (buf == MAP_FAILED) {
pr_err("failed to mmap file\n");
@@ -1357,15 +1370,19 @@ more:
head += size;
file_pos += size;
- ui_progress__update(&prog, size);
+ if (file_pos >= progress_next) {
+ progress_next += file_size / 16;
+ ui_progress__update(file_pos, file_size,
+ "Processing events...");
+ }
+ err = 0;
if (session_done())
- goto out;
+ goto out_err;
if (file_pos < file_size)
goto more;
-out:
/* do the final flush for ordered samples */
session->ordered_samples.next_flush = ULLONG_MAX;
err = flush_sample_queue(session, tool);
@@ -1376,22 +1393,21 @@ out_err:
return err;
}
-int perf_session__process_events(struct perf_session *session,
+int perf_session__process_events(struct perf_session *self,
struct perf_tool *tool)
{
- u64 size = perf_data_file__size(session->file);
int err;
- if (perf_session__register_idle_thread(session) == NULL)
+ if (perf_session__register_idle_thread(self) == NULL)
return -ENOMEM;
- if (!perf_data_file__is_pipe(session->file))
- err = __perf_session__process_events(session,
- session->header.data_offset,
- session->header.data_size,
- size, tool);
+ if (!self->fd_pipe)
+ err = __perf_session__process_events(self,
+ self->header.data_offset,
+ self->header.data_size,
+ self->size, tool);
else
- err = __perf_session__process_pipe_events(session, tool);
+ err = __perf_session__process_pipe_events(self, tool);
return err;
}
@@ -1440,15 +1456,15 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
return 0;
}
-size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp)
+size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
{
- return machines__fprintf_dsos(&session->machines, fp);
+ return machines__fprintf_dsos(&self->machines, fp);
}
-size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
+size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
bool (skip)(struct dso *dso, int parm), int parm)
{
- return machines__fprintf_dsos_buildid(&session->machines, fp, skip, parm);
+ return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
}
size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1509,8 +1525,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
if (symbol_conf.use_callchain && sample->callchain) {
if (machine__resolve_callchain(machine, evsel, al.thread,
- sample, NULL, NULL,
- PERF_MAX_STACK_DEPTH) != 0) {
+ sample, NULL, NULL) != 0) {
if (verbose)
error("Failed to resolve callchain. Skipping\n");
return;
@@ -1614,14 +1629,13 @@ int perf_session__cpu_bitmap(struct perf_session *session,
void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
bool full)
{
- int fd = perf_data_file__fd(session->file);
struct stat st;
int ret;
if (session == NULL || fp == NULL)
return;
- ret = fstat(fd, &st);
+ ret = fstat(session->fd, &st);
if (ret == -1)
return;
@@ -1650,9 +1664,9 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
continue;
err = -EEXIST;
- if (evsel->handler != NULL)
+ if (evsel->handler.func != NULL)
goto out;
- evsel->handler = assocs[i].handler;
+ evsel->handler.func = assocs[i].handler;
}
err = 0;