]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/perf/util/thread-stack.c
perf tools: Add missing headers, mostly stdlib.h
[linux.git] / tools / perf / util / thread-stack.c
index 4ba9e866b076ceb9440eec76bb1133278bd862dc..48d585a0175cc106b63a1498d24e18d46d8a4c58 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/list.h>
 #include <linux/log2.h>
 #include <errno.h>
+#include <stdlib.h>
 #include "thread.h"
 #include "event.h"
 #include "machine.h"
@@ -40,6 +41,8 @@ enum retpoline_state_t {
  * @timestamp: timestamp (if known)
  * @ref: external reference (e.g. db_id of sample)
  * @branch_count: the branch count when the entry was created
+ * @insn_count: the instruction count when the entry was created
+ * @cyc_count the cycle count when the entry was created
  * @db_id: id used for db-export
  * @cp: call path
  * @no_call: a 'call' was not seen
@@ -51,6 +54,8 @@ struct thread_stack_entry {
        u64 timestamp;
        u64 ref;
        u64 branch_count;
+       u64 insn_count;
+       u64 cyc_count;
        u64 db_id;
        struct call_path *cp;
        bool no_call;
@@ -66,6 +71,8 @@ struct thread_stack_entry {
  * @sz: current maximum stack size
  * @trace_nr: current trace number
  * @branch_count: running branch count
+ * @insn_count: running  instruction count
+ * @cyc_count running  cycle count
  * @kernel_start: kernel start address
  * @last_time: last timestamp
  * @crp: call/return processor
@@ -79,6 +86,8 @@ struct thread_stack {
        size_t sz;
        u64 trace_nr;
        u64 branch_count;
+       u64 insn_count;
+       u64 cyc_count;
        u64 kernel_start;
        u64 last_time;
        struct call_return_processor *crp;
@@ -280,6 +289,8 @@ static int thread_stack__call_return(struct thread *thread,
        cr.call_time = tse->timestamp;
        cr.return_time = timestamp;
        cr.branch_count = ts->branch_count - tse->branch_count;
+       cr.insn_count = ts->insn_count - tse->insn_count;
+       cr.cyc_count = ts->cyc_count - tse->cyc_count;
        cr.db_id = tse->db_id;
        cr.call_ref = tse->ref;
        cr.return_ref = ref;
@@ -535,6 +546,8 @@ static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
        tse->timestamp = timestamp;
        tse->ref = ref;
        tse->branch_count = ts->branch_count;
+       tse->insn_count = ts->insn_count;
+       tse->cyc_count = ts->cyc_count;
        tse->cp = cp;
        tse->no_call = no_call;
        tse->trace_end = trace_end;
@@ -616,6 +629,23 @@ static int thread_stack__bottom(struct thread_stack *ts,
                                     true, false);
 }
 
+static int thread_stack__pop_ks(struct thread *thread, struct thread_stack *ts,
+                               struct perf_sample *sample, u64 ref)
+{
+       u64 tm = sample->time;
+       int err;
+
+       /* Return to userspace, so pop all kernel addresses */
+       while (thread_stack__in_kernel(ts)) {
+               err = thread_stack__call_return(thread, ts, --ts->cnt,
+                                               tm, ref, true);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int thread_stack__no_call_return(struct thread *thread,
                                        struct thread_stack *ts,
                                        struct perf_sample *sample,
@@ -635,12 +665,9 @@ static int thread_stack__no_call_return(struct thread *thread,
 
        if (ip >= ks && addr < ks) {
                /* Return to userspace, so pop all kernel addresses */
-               while (thread_stack__in_kernel(ts)) {
-                       err = thread_stack__call_return(thread, ts, --ts->cnt,
-                                                       tm, ref, true);
-                       if (err)
-                               return err;
-               }
+               err = thread_stack__pop_ks(thread, ts, sample, ref);
+               if (err)
+                       return err;
 
                /* If the stack is empty, push the userspace address */
                if (!ts->cnt) {
@@ -650,12 +677,9 @@ static int thread_stack__no_call_return(struct thread *thread,
                }
        } else if (thread_stack__in_kernel(ts) && ip < ks) {
                /* Return to userspace, so pop all kernel addresses */
-               while (thread_stack__in_kernel(ts)) {
-                       err = thread_stack__call_return(thread, ts, --ts->cnt,
-                                                       tm, ref, true);
-                       if (err)
-                               return err;
-               }
+               err = thread_stack__pop_ks(thread, ts, sample, ref);
+               if (err)
+                       return err;
        }
 
        if (ts->cnt)
@@ -865,6 +889,8 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
        }
 
        ts->branch_count += 1;
+       ts->insn_count += sample->insn_cnt;
+       ts->cyc_count += sample->cyc_cnt;
        ts->last_time = sample->time;
 
        if (sample->flags & PERF_IP_FLAG_CALL) {
@@ -896,7 +922,18 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
                        ts->rstate = X86_RETPOLINE_DETECTED;
 
        } else if (sample->flags & PERF_IP_FLAG_RETURN) {
-               if (!sample->ip || !sample->addr)
+               if (!sample->addr) {
+                       u32 return_from_kernel = PERF_IP_FLAG_SYSCALLRET |
+                                                PERF_IP_FLAG_INTERRUPT;
+
+                       if (!(sample->flags & return_from_kernel))
+                               return 0;
+
+                       /* Pop kernel stack */
+                       return thread_stack__pop_ks(thread, ts, sample, ref);
+               }
+
+               if (!sample->ip)
                        return 0;
 
                /* x86 retpoline 'return' doesn't match the stack */