These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / tools / perf / util / session.c
index 0c74012..468de95 100644 (file)
 #include "cpumap.h"
 #include "perf_regs.h"
 #include "asm/bug.h"
+#include "auxtrace.h"
+#include "thread-stack.h"
 
-static int machines__deliver_event(struct machines *machines,
-                                  struct perf_evlist *evlist,
-                                  union perf_event *event,
-                                  struct perf_sample *sample,
-                                  struct perf_tool *tool, u64 file_offset);
+static int perf_session__deliver_event(struct perf_session *session,
+                                      union perf_event *event,
+                                      struct perf_sample *sample,
+                                      struct perf_tool *tool,
+                                      u64 file_offset);
 
 static int perf_session__open(struct perf_session *session)
 {
        struct perf_data_file *file = session->file;
 
        if (perf_session__read_header(session) < 0) {
-               pr_err("incompatible file format (rerun with -v to learn more)");
+               pr_err("incompatible file format (rerun with -v to learn more)\n");
                return -1;
        }
 
@@ -35,17 +37,17 @@ static int perf_session__open(struct perf_session *session)
                return 0;
 
        if (!perf_evlist__valid_sample_type(session->evlist)) {
-               pr_err("non matching sample_type");
+               pr_err("non matching sample_type\n");
                return -1;
        }
 
        if (!perf_evlist__valid_sample_id_all(session->evlist)) {
-               pr_err("non matching sample_id_all");
+               pr_err("non matching sample_id_all\n");
                return -1;
        }
 
        if (!perf_evlist__valid_read_format(session->evlist)) {
-               pr_err("non matching read_format");
+               pr_err("non matching read_format\n");
                return -1;
        }
 
@@ -105,8 +107,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
                return ret;
        }
 
-       return machines__deliver_event(&session->machines, session->evlist, event->event,
-                                      &sample, session->tool, event->file_offset);
+       return perf_session__deliver_event(session, event->event, &sample,
+                                          session->tool, event->file_offset);
 }
 
 struct perf_session *perf_session__new(struct perf_data_file *file,
@@ -119,6 +121,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
 
        session->repipe = repipe;
        session->tool   = tool;
+       INIT_LIST_HEAD(&session->auxtrace_index);
        machines__init(&session->machines);
        ordered_events__init(&session->ordered_events, ordered_events__deliver_event);
 
@@ -135,6 +138,8 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                        perf_session__set_id_hdr_size(session);
                        perf_session__set_comm_exec(session);
                }
+       } else  {
+               session->machines.host.env = &perf_env;
        }
 
        if (!file || perf_data_file__is_write(file)) {
@@ -167,27 +172,13 @@ static void perf_session__delete_threads(struct perf_session *session)
        machine__delete_threads(&session->machines.host);
 }
 
-static void perf_session_env__delete(struct perf_session_env *env)
-{
-       zfree(&env->hostname);
-       zfree(&env->os_release);
-       zfree(&env->version);
-       zfree(&env->arch);
-       zfree(&env->cpu_desc);
-       zfree(&env->cpuid);
-
-       zfree(&env->cmdline);
-       zfree(&env->sibling_cores);
-       zfree(&env->sibling_threads);
-       zfree(&env->numa_nodes);
-       zfree(&env->pmu_mappings);
-}
-
 void perf_session__delete(struct perf_session *session)
 {
+       auxtrace__free(session);
+       auxtrace_index__free(&session->auxtrace_index);
        perf_session__destroy_kernel_maps(session);
        perf_session__delete_threads(session);
-       perf_session_env__delete(&session->header.env);
+       perf_env__exit(&session->header.env);
        machines__exit(&session->machines);
        if (session->file)
                perf_data_file__close(session->file);
@@ -262,6 +253,49 @@ static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
        return 0;
 }
 
+static int process_event_auxtrace_info_stub(struct perf_tool *tool __maybe_unused,
+                               union perf_event *event __maybe_unused,
+                               struct perf_session *session __maybe_unused)
+{
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+static int skipn(int fd, off_t n)
+{
+       char buf[4096];
+       ssize_t ret;
+
+       while (n > 0) {
+               ret = read(fd, buf, min(n, (off_t)sizeof(buf)));
+               if (ret <= 0)
+                       return ret;
+               n -= ret;
+       }
+
+       return 0;
+}
+
+static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
+                                      union perf_event *event,
+                                      struct perf_session *session
+                                      __maybe_unused)
+{
+       dump_printf(": unhandled!\n");
+       if (perf_data_file__is_pipe(session->file))
+               skipn(perf_data_file__fd(session->file), event->auxtrace.size);
+       return event->auxtrace.size;
+}
+
+static
+int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused,
+                                     union perf_event *event __maybe_unused,
+                                     struct perf_session *session __maybe_unused)
+{
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
 void perf_tool__fill_defaults(struct perf_tool *tool)
 {
        if (tool->sample == NULL)
@@ -278,6 +312,14 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->exit = process_event_stub;
        if (tool->lost == NULL)
                tool->lost = perf_event__process_lost;
+       if (tool->lost_samples == NULL)
+               tool->lost_samples = perf_event__process_lost_samples;
+       if (tool->aux == NULL)
+               tool->aux = perf_event__process_aux;
+       if (tool->itrace_start == NULL)
+               tool->itrace_start = perf_event__process_itrace_start;
+       if (tool->context_switch == NULL)
+               tool->context_switch = perf_event__process_switch;
        if (tool->read == NULL)
                tool->read = process_event_sample_stub;
        if (tool->throttle == NULL)
@@ -298,6 +340,12 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
        }
        if (tool->id_index == NULL)
                tool->id_index = process_id_index_stub;
+       if (tool->auxtrace_info == NULL)
+               tool->auxtrace_info = process_event_auxtrace_info_stub;
+       if (tool->auxtrace == NULL)
+               tool->auxtrace = process_event_auxtrace_stub;
+       if (tool->auxtrace_error == NULL)
+               tool->auxtrace_error = process_event_auxtrace_error_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -390,6 +438,39 @@ 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__aux_swap(union perf_event *event, bool sample_id_all)
+{
+       event->aux.aux_offset = bswap_64(event->aux.aux_offset);
+       event->aux.aux_size   = bswap_64(event->aux.aux_size);
+       event->aux.flags      = bswap_64(event->aux.flags);
+
+       if (sample_id_all)
+               swap_sample_id_all(event, &event->aux + 1);
+}
+
+static void perf_event__itrace_start_swap(union perf_event *event,
+                                         bool sample_id_all)
+{
+       event->itrace_start.pid  = bswap_32(event->itrace_start.pid);
+       event->itrace_start.tid  = bswap_32(event->itrace_start.tid);
+
+       if (sample_id_all)
+               swap_sample_id_all(event, &event->itrace_start + 1);
+}
+
+static void perf_event__switch_swap(union perf_event *event, bool sample_id_all)
+{
+       if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) {
+               event->context_switch.next_prev_pid =
+                               bswap_32(event->context_switch.next_prev_pid);
+               event->context_switch.next_prev_tid =
+                               bswap_32(event->context_switch.next_prev_tid);
+       }
+
+       if (sample_id_all)
+               swap_sample_id_all(event, &event->context_switch + 1);
+}
+
 static void perf_event__throttle_swap(union perf_event *event,
                                      bool sample_id_all)
 {
@@ -438,19 +519,42 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
 {
        attr->type              = bswap_32(attr->type);
        attr->size              = bswap_32(attr->size);
-       attr->config            = bswap_64(attr->config);
-       attr->sample_period     = bswap_64(attr->sample_period);
-       attr->sample_type       = bswap_64(attr->sample_type);
-       attr->read_format       = bswap_64(attr->read_format);
-       attr->wakeup_events     = bswap_32(attr->wakeup_events);
-       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));
+#define bswap_safe(f, n)                                       \
+       (attr->size > (offsetof(struct perf_event_attr, f) +    \
+                      sizeof(attr->f) * (n)))
+#define bswap_field(f, sz)                     \
+do {                                           \
+       if (bswap_safe(f, 0))                   \
+               attr->f = bswap_##sz(attr->f);  \
+} while(0)
+#define bswap_field_32(f) bswap_field(f, 32)
+#define bswap_field_64(f) bswap_field(f, 64)
+
+       bswap_field_64(config);
+       bswap_field_64(sample_period);
+       bswap_field_64(sample_type);
+       bswap_field_64(read_format);
+       bswap_field_32(wakeup_events);
+       bswap_field_32(bp_type);
+       bswap_field_64(bp_addr);
+       bswap_field_64(bp_len);
+       bswap_field_64(branch_sample_type);
+       bswap_field_64(sample_regs_user);
+       bswap_field_32(sample_stack_user);
+       bswap_field_32(aux_watermark);
+
+       /*
+        * After read_format are bitfields. Check read_format because
+        * we are unable to use offsetof on bitfield.
+        */
+       if (bswap_safe(read_format, 1))
+               swap_bitfield((u8 *) (&attr->read_format + 1),
+                             sizeof(u64));
+#undef bswap_field_64
+#undef bswap_field_32
+#undef bswap_field
+#undef bswap_safe
 }
 
 static void perf_event__hdr_attr_swap(union perf_event *event,
@@ -478,6 +582,40 @@ static void perf_event__tracing_data_swap(union perf_event *event,
        event->tracing_data.size = bswap_32(event->tracing_data.size);
 }
 
+static void perf_event__auxtrace_info_swap(union perf_event *event,
+                                          bool sample_id_all __maybe_unused)
+{
+       size_t size;
+
+       event->auxtrace_info.type = bswap_32(event->auxtrace_info.type);
+
+       size = event->header.size;
+       size -= (void *)&event->auxtrace_info.priv - (void *)event;
+       mem_bswap_64(event->auxtrace_info.priv, size);
+}
+
+static void perf_event__auxtrace_swap(union perf_event *event,
+                                     bool sample_id_all __maybe_unused)
+{
+       event->auxtrace.size      = bswap_64(event->auxtrace.size);
+       event->auxtrace.offset    = bswap_64(event->auxtrace.offset);
+       event->auxtrace.reference = bswap_64(event->auxtrace.reference);
+       event->auxtrace.idx       = bswap_32(event->auxtrace.idx);
+       event->auxtrace.tid       = bswap_32(event->auxtrace.tid);
+       event->auxtrace.cpu       = bswap_32(event->auxtrace.cpu);
+}
+
+static void perf_event__auxtrace_error_swap(union perf_event *event,
+                                           bool sample_id_all __maybe_unused)
+{
+       event->auxtrace_error.type = bswap_32(event->auxtrace_error.type);
+       event->auxtrace_error.code = bswap_32(event->auxtrace_error.code);
+       event->auxtrace_error.cpu  = bswap_32(event->auxtrace_error.cpu);
+       event->auxtrace_error.pid  = bswap_32(event->auxtrace_error.pid);
+       event->auxtrace_error.tid  = bswap_32(event->auxtrace_error.tid);
+       event->auxtrace_error.ip   = bswap_64(event->auxtrace_error.ip);
+}
+
 typedef void (*perf_event__swap_op)(union perf_event *event,
                                    bool sample_id_all);
 
@@ -492,11 +630,19 @@ static perf_event__swap_op perf_event__swap_ops[] = {
        [PERF_RECORD_THROTTLE]            = perf_event__throttle_swap,
        [PERF_RECORD_UNTHROTTLE]          = perf_event__throttle_swap,
        [PERF_RECORD_SAMPLE]              = perf_event__all64_swap,
+       [PERF_RECORD_AUX]                 = perf_event__aux_swap,
+       [PERF_RECORD_ITRACE_START]        = perf_event__itrace_start_swap,
+       [PERF_RECORD_LOST_SAMPLES]        = perf_event__all64_swap,
+       [PERF_RECORD_SWITCH]              = perf_event__switch_swap,
+       [PERF_RECORD_SWITCH_CPU_WIDE]     = perf_event__switch_swap,
        [PERF_RECORD_HEADER_ATTR]         = perf_event__hdr_attr_swap,
        [PERF_RECORD_HEADER_EVENT_TYPE]   = perf_event__event_type_swap,
        [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
        [PERF_RECORD_HEADER_BUILD_ID]     = NULL,
        [PERF_RECORD_ID_INDEX]            = perf_event__all64_swap,
+       [PERF_RECORD_AUXTRACE_INFO]       = perf_event__auxtrace_info_swap,
+       [PERF_RECORD_AUXTRACE]            = perf_event__auxtrace_swap,
+       [PERF_RECORD_AUXTRACE_ERROR]      = perf_event__auxtrace_error_swap,
        [PERF_RECORD_HEADER_MAX]          = NULL,
 };
 
@@ -543,6 +689,8 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused,
                                  union perf_event *event __maybe_unused,
                                  struct ordered_events *oe)
 {
+       if (dump_trace)
+               fprintf(stdout, "\n");
        return ordered_events__flush(oe, OE_FLUSH__ROUND);
 }
 
@@ -621,10 +769,18 @@ static void branch_stack__printf(struct perf_sample *sample)
 
        printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr);
 
-       for (i = 0; i < sample->branch_stack->nr; i++)
-               printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 "\n",
-                       i, sample->branch_stack->entries[i].from,
-                       sample->branch_stack->entries[i].to);
+       for (i = 0; i < sample->branch_stack->nr; i++) {
+               struct branch_entry *e = &sample->branch_stack->entries[i];
+
+               printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x\n",
+                       i, e->from, e->to,
+                       e->flags.cycles,
+                       e->flags.mispred ? "M" : " ",
+                       e->flags.predicted ? "P" : " ",
+                       e->flags.abort ? "A" : " ",
+                       e->flags.in_tx ? "T" : " ",
+                       (unsigned)e->flags.reserved);
+       }
 }
 
 static void regs_dump__printf(u64 mask, u64 *regs)
@@ -816,7 +972,7 @@ static struct machine *machines__find_for_cpumode(struct machines *machines,
 
                machine = machines__find(machines, pid);
                if (!machine)
-                       machine = machines__find(machines, DEFAULT_GUEST_KERNEL_ID);
+                       machine = machines__findnew(machines, DEFAULT_GUEST_KERNEL_ID);
                return machine;
        }
 
@@ -908,11 +1064,11 @@ static int machines__deliver_event(struct machines *machines,
 
        switch (event->header.type) {
        case PERF_RECORD_SAMPLE:
-               dump_sample(evsel, event, sample);
                if (evsel == NULL) {
                        ++evlist->stats.nr_unknown_id;
                        return 0;
                }
+               dump_sample(evsel, event, sample);
                if (machine == NULL) {
                        ++evlist->stats.nr_unprocessable_samples;
                        return 0;
@@ -921,6 +1077,8 @@ static int machines__deliver_event(struct machines *machines,
        case PERF_RECORD_MMAP:
                return tool->mmap(tool, event, sample, machine);
        case PERF_RECORD_MMAP2:
+               if (event->header.misc & PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT)
+                       ++evlist->stats.nr_proc_map_timeout;
                return tool->mmap2(tool, event, sample, machine);
        case PERF_RECORD_COMM:
                return tool->comm(tool, event, sample, machine);
@@ -932,18 +1090,50 @@ static int machines__deliver_event(struct machines *machines,
                if (tool->lost == perf_event__process_lost)
                        evlist->stats.total_lost += event->lost.lost;
                return tool->lost(tool, event, sample, machine);
+       case PERF_RECORD_LOST_SAMPLES:
+               if (tool->lost_samples == perf_event__process_lost_samples)
+                       evlist->stats.total_lost_samples += event->lost_samples.lost;
+               return tool->lost_samples(tool, event, sample, machine);
        case PERF_RECORD_READ:
                return tool->read(tool, event, sample, evsel, machine);
        case PERF_RECORD_THROTTLE:
                return tool->throttle(tool, event, sample, machine);
        case PERF_RECORD_UNTHROTTLE:
                return tool->unthrottle(tool, event, sample, machine);
+       case PERF_RECORD_AUX:
+               if (tool->aux == perf_event__process_aux &&
+                   (event->aux.flags & PERF_AUX_FLAG_TRUNCATED))
+                       evlist->stats.total_aux_lost += 1;
+               return tool->aux(tool, event, sample, machine);
+       case PERF_RECORD_ITRACE_START:
+               return tool->itrace_start(tool, event, sample, machine);
+       case PERF_RECORD_SWITCH:
+       case PERF_RECORD_SWITCH_CPU_WIDE:
+               return tool->context_switch(tool, event, sample, machine);
        default:
                ++evlist->stats.nr_unknown_events;
                return -1;
        }
 }
 
+static int perf_session__deliver_event(struct perf_session *session,
+                                      union perf_event *event,
+                                      struct perf_sample *sample,
+                                      struct perf_tool *tool,
+                                      u64 file_offset)
+{
+       int ret;
+
+       ret = auxtrace__process_event(session, event, sample, tool);
+       if (ret < 0)
+               return ret;
+       if (ret > 0)
+               return 0;
+
+       return machines__deliver_event(&session->machines, session->evlist,
+                                      event, sample, tool, file_offset);
+}
+
 static s64 perf_session__process_user_event(struct perf_session *session,
                                            union perf_event *event,
                                            u64 file_offset)
@@ -980,6 +1170,15 @@ static s64 perf_session__process_user_event(struct perf_session *session,
                return tool->finished_round(tool, event, oe);
        case PERF_RECORD_ID_INDEX:
                return tool->id_index(tool, event, session);
+       case PERF_RECORD_AUXTRACE_INFO:
+               return tool->auxtrace_info(tool, event, session);
+       case PERF_RECORD_AUXTRACE:
+               /* setup for reading amidst mmap */
+               lseek(fd, file_offset + event->header.size, SEEK_SET);
+               return tool->auxtrace(tool, event, session);
+       case PERF_RECORD_AUXTRACE_ERROR:
+               perf_session__auxtrace_error_inc(session, event);
+               return tool->auxtrace_error(tool, event, session);
        default:
                return -EINVAL;
        }
@@ -1034,7 +1233,7 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
                return -1;
 
        if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||
-           readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz)
+           readn(fd, buf, hdr_sz) != (ssize_t)hdr_sz)
                return -1;
 
        event = (union perf_event *)buf;
@@ -1042,12 +1241,12 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
        if (session->header.needs_swap)
                perf_event_header__bswap(&event->header);
 
-       if (event->header.size < hdr_sz)
+       if (event->header.size < hdr_sz || event->header.size > buf_sz)
                return -1;
 
        rest = event->header.size - hdr_sz;
 
-       if (readn(fd, &buf, rest) != (ssize_t)rest)
+       if (readn(fd, buf, rest) != (ssize_t)rest)
                return -1;
 
        if (session->header.needs_swap)
@@ -1096,8 +1295,8 @@ static s64 perf_session__process_event(struct perf_session *session,
                        return ret;
        }
 
-       return machines__deliver_event(&session->machines, evlist, event,
-                                      &sample, tool, file_offset);
+       return perf_session__deliver_event(session, event, &sample, tool,
+                                          file_offset);
 }
 
 void perf_event_header__bswap(struct perf_event_header *hdr)
@@ -1112,7 +1311,7 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
        return machine__findnew_thread(&session->machines.host, -1, pid);
 }
 
-static struct thread *perf_session__register_idle_thread(struct perf_session *session)
+struct thread *perf_session__register_idle_thread(struct perf_session *session)
 {
        struct thread *thread;
 
@@ -1138,6 +1337,25 @@ static void perf_session__warn_about_errors(const struct perf_session *session)
                            stats->nr_events[PERF_RECORD_LOST]);
        }
 
+       if (session->tool->lost_samples == perf_event__process_lost_samples) {
+               double drop_rate;
+
+               drop_rate = (double)stats->total_lost_samples /
+                           (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples);
+               if (drop_rate > 0.05) {
+                       ui__warning("Processed %" PRIu64 " samples and lost %3.2f%% samples!\n\n",
+                                   stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples,
+                                   drop_rate * 100.0);
+               }
+       }
+
+       if (session->tool->aux == perf_event__process_aux &&
+           stats->total_aux_lost != 0) {
+               ui__warning("AUX data lost %" PRIu64 " times out of %u!\n\n",
+                           stats->total_aux_lost,
+                           stats->nr_events[PERF_RECORD_AUX]);
+       }
+
        if (stats->nr_unknown_events != 0) {
                ui__warning("Found %u unknown events!\n\n"
                            "Is this an older tool processing a perf.data "
@@ -1168,6 +1386,32 @@ static void perf_session__warn_about_errors(const struct perf_session *session)
 
        if (oe->nr_unordered_events != 0)
                ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events);
+
+       events_stats__auxtrace_error_warn(stats);
+
+       if (stats->nr_proc_map_timeout != 0) {
+               ui__warning("%d map information files for pre-existing threads were\n"
+                           "not processed, if there are samples for addresses they\n"
+                           "will not be resolved, you may find out which are these\n"
+                           "threads by running with -v and redirecting the output\n"
+                           "to a file.\n"
+                           "The time limit to process proc map is too short?\n"
+                           "Increase it by --proc-map-timeout\n",
+                           stats->nr_proc_map_timeout);
+       }
+}
+
+static int perf_session__flush_thread_stack(struct thread *thread,
+                                           void *p __maybe_unused)
+{
+       return thread_stack__flush(thread);
+}
+
+static int perf_session__flush_thread_stacks(struct perf_session *session)
+{
+       return machines__for_each_thread(&session->machines,
+                                        perf_session__flush_thread_stack,
+                                        NULL);
 }
 
 volatile int session_done;
@@ -1256,10 +1500,17 @@ more:
 done:
        /* do the final flush for ordered samples */
        err = ordered_events__flush(oe, OE_FLUSH__FINAL);
+       if (err)
+               goto out_err;
+       err = auxtrace__flush_events(session, tool);
+       if (err)
+               goto out_err;
+       err = perf_session__flush_thread_stacks(session);
 out_err:
        free(buf);
        perf_session__warn_about_errors(session);
        ordered_events__free(&session->ordered_events);
+       auxtrace__free_events(session);
        return err;
 }
 
@@ -1324,7 +1575,10 @@ static int __perf_session__process_events(struct perf_session *session,
        file_offset = page_offset;
        head = data_offset - page_offset;
 
-       if (data_size && (data_offset + data_size < file_size))
+       if (data_size == 0)
+               goto out;
+
+       if (data_offset + data_size < file_size)
                file_size = data_offset + data_size;
 
        ui_progress__init(&prog, file_size, "Processing events...");
@@ -1402,10 +1656,17 @@ more:
 out:
        /* do the final flush for ordered samples */
        err = ordered_events__flush(oe, OE_FLUSH__FINAL);
+       if (err)
+               goto out_err;
+       err = auxtrace__flush_events(session, tool);
+       if (err)
+               goto out_err;
+       err = perf_session__flush_thread_stacks(session);
 out_err:
        ui_progress__finish();
        perf_session__warn_about_errors(session);
        ordered_events__free(&session->ordered_events);
+       auxtrace__free_events(session);
        session->one_mmap = false;
        return err;
 }
@@ -1488,7 +1749,13 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp
 
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
 {
-       size_t ret = fprintf(fp, "Aggregated stats:\n");
+       size_t ret;
+       const char *msg = "";
+
+       if (perf_header__has_feat(&session->header, HEADER_AUXTRACE))
+               msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)";
+
+       ret = fprintf(fp, "\nAggregated stats:%s\n", msg);
 
        ret += events_stats__fprintf(&session->evlist->stats, fp);
        return ret;
@@ -1533,7 +1800,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
 
                if (thread__resolve_callchain(al->thread, evsel,
                                              sample, NULL, NULL,
-                                             PERF_MAX_STACK_DEPTH) != 0) {
+                                             stack_depth) != 0) {
                        if (verbose)
                                error("Failed to resolve callchain. Skipping\n");
                        return;
@@ -1655,7 +1922,7 @@ int perf_session__cpu_bitmap(struct perf_session *session,
        err = 0;
 
 out_delete_map:
-       cpu_map__delete(map);
+       cpu_map__put(map);
        return err;
 }