perf intel-pt: Time filter logged perf events
[linux-2.6-microblaze.git] / tools / perf / util / intel-pt.c
index cb3c1e5..0715d6e 100644 (file)
@@ -236,7 +236,7 @@ static void intel_pt_log_event(union perf_event *event)
        if (!intel_pt_enable_logging || !f)
                return;
 
-       perf_event__fprintf(event, f);
+       perf_event__fprintf(event, NULL, f);
 }
 
 static void intel_pt_dump_sample(struct perf_session *session,
@@ -249,6 +249,24 @@ static void intel_pt_dump_sample(struct perf_session *session,
        intel_pt_dump(pt, sample->aux_sample.data, sample->aux_sample.size);
 }
 
+static bool intel_pt_log_events(struct intel_pt *pt, u64 tm)
+{
+       struct perf_time_interval *range = pt->synth_opts.ptime_range;
+       int n = pt->synth_opts.range_num;
+
+       if (pt->synth_opts.log_plus_flags & AUXTRACE_LOG_FLG_ALL_PERF_EVTS)
+               return true;
+
+       if (pt->synth_opts.log_minus_flags & AUXTRACE_LOG_FLG_ALL_PERF_EVTS)
+               return false;
+
+       /* perf_time__ranges_skip_sample does not work if time is zero */
+       if (!tm)
+               tm = 1;
+
+       return !n || !perf_time__ranges_skip_sample(range, n, tm);
+}
+
 static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
                                   struct auxtrace_buffer *b)
 {
@@ -520,6 +538,17 @@ intel_pt_cache_lookup(struct dso *dso, struct machine *machine, u64 offset)
        return auxtrace_cache__lookup(dso->auxtrace_cache, offset);
 }
 
+static void intel_pt_cache_invalidate(struct dso *dso, struct machine *machine,
+                                     u64 offset)
+{
+       struct auxtrace_cache *c = intel_pt_cache(dso, machine);
+
+       if (!c)
+               return;
+
+       auxtrace_cache__remove(dso->auxtrace_cache, offset);
+}
+
 static inline u8 intel_pt_cpumode(struct intel_pt *pt, uint64_t ip)
 {
        return ip >= pt->kernel_start ?
@@ -1852,6 +1881,15 @@ static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu,
        char msg[MAX_AUXTRACE_ERROR_MSG];
        int err;
 
+       if (pt->synth_opts.error_minus_flags) {
+               if (code == INTEL_PT_ERR_OVR &&
+                   pt->synth_opts.error_minus_flags & AUXTRACE_ERR_FLG_OVERFLOW)
+                       return 0;
+               if (code == INTEL_PT_ERR_LOST &&
+                   pt->synth_opts.error_minus_flags & AUXTRACE_ERR_FLG_DATA_LOST)
+                       return 0;
+       }
+
        intel_pt__strerror(code, msg, MAX_AUXTRACE_ERROR_MSG);
 
        auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
@@ -2566,10 +2604,6 @@ static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event,
                return -EINVAL;
        }
 
-       intel_pt_log("context_switch: cpu %d pid %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
-                    cpu, pid, tid, sample->time, perf_time_to_tsc(sample->time,
-                    &pt->tc));
-
        ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
        if (ret <= 0)
                return ret;
@@ -2594,6 +2628,67 @@ static int intel_pt_process_itrace_start(struct intel_pt *pt,
                                        event->itrace_start.tid);
 }
 
+static int intel_pt_find_map(struct thread *thread, u8 cpumode, u64 addr,
+                            struct addr_location *al)
+{
+       if (!al->map || addr < al->map->start || addr >= al->map->end) {
+               if (!thread__find_map(thread, cpumode, addr, al))
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* Invalidate all instruction cache entries that overlap the text poke */
+static int intel_pt_text_poke(struct intel_pt *pt, union perf_event *event)
+{
+       u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+       u64 addr = event->text_poke.addr + event->text_poke.new_len - 1;
+       /* Assume text poke begins in a basic block no more than 4096 bytes */
+       int cnt = 4096 + event->text_poke.new_len;
+       struct thread *thread = pt->unknown_thread;
+       struct addr_location al = { .map = NULL };
+       struct machine *machine = pt->machine;
+       struct intel_pt_cache_entry *e;
+       u64 offset;
+
+       if (!event->text_poke.new_len)
+               return 0;
+
+       for (; cnt; cnt--, addr--) {
+               if (intel_pt_find_map(thread, cpumode, addr, &al)) {
+                       if (addr < event->text_poke.addr)
+                               return 0;
+                       continue;
+               }
+
+               if (!al.map->dso || !al.map->dso->auxtrace_cache)
+                       continue;
+
+               offset = al.map->map_ip(al.map, addr);
+
+               e = intel_pt_cache_lookup(al.map->dso, machine, offset);
+               if (!e)
+                       continue;
+
+               if (addr + e->byte_cnt + e->length <= event->text_poke.addr) {
+                       /*
+                        * No overlap. Working backwards there cannot be another
+                        * basic block that overlaps the text poke if there is a
+                        * branch instruction before the text poke address.
+                        */
+                       if (e->branch != INTEL_PT_BR_NO_BRANCH)
+                               return 0;
+               } else {
+                       intel_pt_cache_invalidate(al.map->dso, machine, offset);
+                       intel_pt_log("Invalidated instruction cache for %s at %#"PRIx64"\n",
+                                    al.map->dso->long_name, addr);
+               }
+       }
+
+       return 0;
+}
+
 static int intel_pt_process_event(struct perf_session *session,
                                  union perf_event *event,
                                  struct perf_sample *sample,
@@ -2662,9 +2757,14 @@ static int intel_pt_process_event(struct perf_session *session,
                 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
                err = intel_pt_context_switch(pt, event, sample);
 
-       intel_pt_log("event %u: cpu %d time %"PRIu64" tsc %#"PRIx64" ",
-                    event->header.type, sample->cpu, sample->time, timestamp);
-       intel_pt_log_event(event);
+       if (!err && event->header.type == PERF_RECORD_TEXT_POKE)
+               err = intel_pt_text_poke(pt, event);
+
+       if (intel_pt_enable_logging && intel_pt_log_events(pt, sample->time)) {
+               intel_pt_log("event %u: cpu %d time %"PRIu64" tsc %#"PRIx64" ",
+                            event->header.type, sample->cpu, sample->time, timestamp);
+               intel_pt_log_event(event);
+       }
 
        return err;
 }