misc: tegra-profiler: add unwind information
Igor Nabirushkin [Fri, 16 May 2014 08:49:15 +0000 (12:49 +0400)]
Tegra Profiler: add additional unwind information
for each call entry.

Bug 1514626

Change-Id: I2873941a4c903e0e7e909897ead55eb34d80b966
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/410770
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Tested-by: Daniel Horowitz <dhorowitz@nvidia.com>
Tested-by: Maxim Morin <mmorin@nvidia.com>

drivers/misc/tegra-profiler/backtrace.c
drivers/misc/tegra-profiler/backtrace.h
drivers/misc/tegra-profiler/comm.c
drivers/misc/tegra-profiler/eh_unwind.c
drivers/misc/tegra-profiler/hrt.c
drivers/misc/tegra-profiler/main.c
drivers/misc/tegra-profiler/quadd_proc.c
drivers/misc/tegra-profiler/version.h
include/linux/tegra_profiler.h

index 371bd24..f1f3023 100644 (file)
@@ -77,9 +77,21 @@ quadd_user_link_register(struct pt_regs *regs)
 #endif
 }
 
+static inline void
+put_unw_type(u32 *p, int bt_idx, unsigned int type)
+{
+       int word_idx, shift;
+
+       word_idx = bt_idx / 8;
+       shift = (bt_idx % 8) * 4;
+
+       *(p + word_idx) &= ~(0x0f << shift);
+       *(p + word_idx) |= (type & 0x0f) << shift;
+}
+
 int
 quadd_callchain_store(struct quadd_callchain *cc,
-                     unsigned long ip)
+                     unsigned long ip, unsigned int type)
 {
        if (!ip) {
                cc->unw_rc = QUADD_URC_PC_INCORRECT;
@@ -91,6 +103,8 @@ quadd_callchain_store(struct quadd_callchain *cc,
                return 0;
        }
 
+       put_unw_type(cc->types, cc->nr, type);
+
        if (cc->cs_64)
                cc->ip_64[cc->nr++] = ip;
        else
@@ -150,7 +164,7 @@ user_backtrace(unsigned long __user *tail,
                return NULL;
        }
 
-       nr_added = quadd_callchain_store(cc, value_lr);
+       nr_added = quadd_callchain_store(cc, value_lr, QUADD_UNW_TYPE_FP);
        if (nr_added == 0)
                return NULL;
 
@@ -233,7 +247,8 @@ get_user_callchain_fp(struct pt_regs *regs,
                                return 0;
                        }
 
-                       nr_added = quadd_callchain_store(cc, lr);
+                       nr_added = quadd_callchain_store(cc, lr,
+                                                        QUADD_UNW_TYPE_LR_FP);
                        if (nr_added == 0)
                                return cc->nr;
 
@@ -330,7 +345,7 @@ user_backtrace_compat(u32 __user *tail,
                return NULL;
        }
 
-       nr_added = quadd_callchain_store(cc, value_lr);
+       nr_added = quadd_callchain_store(cc, value_lr, QUADD_UNW_TYPE_FP);
        if (nr_added == 0)
                return NULL;
 
@@ -413,7 +428,8 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
                                return 0;
                        }
 
-                       nr_added = quadd_callchain_store(cc, lr);
+                       nr_added = quadd_callchain_store(cc, lr,
+                                                        QUADD_UNW_TYPE_LR_FP);
                        if (nr_added == 0)
                                return cc->nr;
 
index 47fad09..ebdd1de 100644 (file)
 #define __QUADD_BACKTRACE_H
 
 #include <linux/mm.h>
+#include <linux/bitops.h>
 
 #define QUADD_MAX_STACK_DEPTH          64
 
+#define QUADD_UNW_TYPES_SIZE \
+       DIV_ROUND_UP(QUADD_MAX_STACK_DEPTH * 4, sizeof(u32) * BITS_PER_BYTE)
+
 struct quadd_callchain {
        int nr;
 
@@ -29,6 +33,8 @@ struct quadd_callchain {
                u64 ip_64[QUADD_MAX_STACK_DEPTH];
        };
 
+       u32 types[QUADD_UNW_TYPES_SIZE];
+
        int cs_64;
 
        unsigned int unw_method;
@@ -49,7 +55,7 @@ quadd_get_user_callchain(struct pt_regs *regs,
 
 int
 quadd_callchain_store(struct quadd_callchain *cc,
-                     unsigned long ip);
+                     unsigned long ip, unsigned int type);
 
 unsigned long
 quadd_user_stack_pointer(struct pt_regs *regs);
index 9820f42..428059a 100644 (file)
@@ -254,7 +254,7 @@ static ssize_t read_sample(char __user *buffer, size_t max_length)
 {
        u32 sed;
        unsigned int type;
-       int retval = -EIO, ip_size;
+       int retval = -EIO, ip_size, bt_size;
        int was_read = 0, write_offset = 0;
        unsigned long flags;
        struct quadd_ring_buffer *rb = &comm_ctx.rb;
@@ -294,7 +294,12 @@ static ssize_t read_sample(char __user *buffer, size_t max_length)
                ip_size = (sed & QUADD_SED_IP64) ?
                        sizeof(u64) : sizeof(u32);
 
-               length_extra = sample->callchain_nr * ip_size;
+               bt_size = sample->callchain_nr;
+
+               length_extra = bt_size * ip_size;
+
+               if (bt_size > 0)
+                       length_extra += DIV_ROUND_UP(bt_size, 8) * sizeof(u32);
 
                nr_events = __sw_hweight32(sample->events_flags);
                length_extra += nr_events * sizeof(u32);
index af809a2..d97edfb 100644 (file)
@@ -833,7 +833,8 @@ unwind_exec_insn(struct quadd_extabs_mmap *mmap,
 static long
 unwind_frame(struct ex_region_info *ri,
             struct stackframe *frame,
-            struct vm_area_struct *vma_sp)
+            struct vm_area_struct *vma_sp,
+            unsigned int *unw_type)
 {
        unsigned long high, low;
        const struct unwind_idx *idx;
@@ -913,8 +914,12 @@ unwind_frame(struct ex_region_info *ri,
                        return -QUADD_URC_SP_INCORRECT;
        }
 
-       if (ctrl.vrs[PC] == 0)
+       if (ctrl.vrs[PC] == 0) {
                ctrl.vrs[PC] = ctrl.vrs[LR];
+               *unw_type = QUADD_UNW_TYPE_LR_UT;
+       } else {
+               *unw_type = QUADD_UNW_TYPE_UT;
+       }
 
        if (!validate_pc_addr(ctrl.vrs[PC], sizeof(u32)))
                return -QUADD_URC_PC_INCORRECT;
@@ -936,6 +941,7 @@ unwind_backtrace(struct quadd_callchain *cc,
                 struct vm_area_struct *vma_sp,
                 struct task_struct *task)
 {
+       unsigned int unw_type;
        struct ex_region_info ri_new;
        struct stackframe frame;
 
@@ -988,7 +994,7 @@ unwind_backtrace(struct quadd_callchain *cc,
                        ri = &ri_new;
                }
 
-               err = unwind_frame(ri, &frame, vma_sp);
+               err = unwind_frame(ri, &frame, vma_sp, &unw_type);
                if (err < 0) {
                        pr_debug("end unwind, urc: %ld\n", err);
                        cc->unw_rc = -err;
@@ -1001,7 +1007,7 @@ unwind_backtrace(struct quadd_callchain *cc,
                cc->curr_sp = frame.sp;
                cc->curr_fp = frame.fp_arm;
 
-               nr_added = quadd_callchain_store(cc, frame.pc);
+               nr_added = quadd_callchain_store(cc, frame.pc, unw_type);
                if (nr_added == 0)
                        break;
        }
index 8c2b6b7..9bbcb30 100644 (file)
@@ -237,7 +237,7 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task)
        int i, vec_idx = 0, bt_size = 0;
        int nr_events = 0, nr_positive_events = 0;
        struct pt_regs *user_regs;
-       struct quadd_iovec vec[4];
+       struct quadd_iovec vec[5];
        struct hrt_event_value events[QUADD_MAX_COUNTERS];
        u32 events_extra[QUADD_MAX_COUNTERS];
 
@@ -306,16 +306,22 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task)
 #else
                        cc->cs_64 = 0;
 #endif
-                       bt_size += quadd_callchain_store(cc, pc);
+                       bt_size += quadd_callchain_store(cc, pc,
+                                                        QUADD_UNW_TYPE_KCTX);
                }
 
                if (bt_size > 0) {
                        int ip_size = cc->cs_64 ? sizeof(u64) : sizeof(u32);
+                       int nr_types = DIV_ROUND_UP(bt_size, 8);
 
                        vec[vec_idx].base = cc->cs_64 ?
                                (void *)cc->ip_64 : (void *)cc->ip_32;
                        vec[vec_idx].len = bt_size * ip_size;
                        vec_idx++;
+
+                       vec[vec_idx].base = cc->types;
+                       vec[vec_idx].len = nr_types * sizeof(cc->types[0]);
+                       vec_idx++;
                }
 
                extra_data |= cc->unw_method << QUADD_SED_UNW_METHOD_SHIFT;
index 786cb1b..da0c15f 100644 (file)
@@ -430,6 +430,7 @@ static void get_capabilities(struct quadd_comm_cap *cap)
        extra |= QUADD_COMM_CAP_EXTRA_SUPPORT_AARCH64;
        extra |= QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP;
        extra |= QUADD_COMM_CAP_EXTRA_UNWIND_MIXED;
+       extra |= QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE;
 
        cap->reserved[QUADD_COMM_CAP_IDX_EXTRA] = extra;
 }
index d7464f1..b7993e8 100644 (file)
@@ -89,6 +89,8 @@ static int show_capabilities(struct seq_file *f, void *offset)
                   YES_NO(extra & QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP));
        seq_printf(f, "support mixed unwinding mode:          %s\n",
                   YES_NO(extra & QUADD_COMM_CAP_EXTRA_UNWIND_MIXED));
+       seq_printf(f, "information about unwind entry:        %s\n",
+                  YES_NO(extra & QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE));
 
        seq_puts(f, "\n");
        seq_puts(f, "Supported events:\n");
index 71ed6f8..62a1b02 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __QUADD_VERSION_H
 #define __QUADD_VERSION_H
 
-#define QUADD_MODULE_VERSION           "1.69"
+#define QUADD_MODULE_VERSION           "1.70"
 #define QUADD_MODULE_BRANCH            "Dev"
 
 #endif /* __QUADD_VERSION_H */
index fe65583..bfab1ee 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <linux/ioctl.h>
 
-#define QUADD_SAMPLES_VERSION  25
+#define QUADD_SAMPLES_VERSION  26
 #define QUADD_IO_VERSION       12
 
 #define QUADD_IO_VERSION_DYNAMIC_RB            5
@@ -38,6 +38,7 @@
 #define QUADD_SAMPLE_VERSION_SUPPORT_IP64      23
 #define QUADD_SAMPLE_VERSION_SPECIAL_MMAP      24
 #define QUADD_SAMPLE_VERSION_UNWIND_MIXED      25
+#define QUADD_SAMPLE_VERSION_UNW_ENTRY_TYPE    26
 
 #define QUADD_MAX_COUNTERS     32
 #define QUADD_MAX_PROCESS      64
@@ -175,6 +176,14 @@ enum {
 #define QUADD_SED_UNW_METHOD_SHIFT     1
 #define QUADD_SED_UNW_METHOD_MASK      (0x07 << QUADD_SED_UNW_METHOD_SHIFT)
 
+enum {
+       QUADD_UNW_TYPE_FP = 0,
+       QUADD_UNW_TYPE_UT,
+       QUADD_UNW_TYPE_LR_FP,
+       QUADD_UNW_TYPE_LR_UT,
+       QUADD_UNW_TYPE_KCTX,
+};
+
 struct quadd_sample_data {
        u64 ip;
        u32 pid;
@@ -358,6 +367,7 @@ enum {
 #define QUADD_COMM_CAP_EXTRA_SUPPORT_AARCH64   (1 << 4)
 #define QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP (1 << 5)
 #define QUADD_COMM_CAP_EXTRA_UNWIND_MIXED      (1 << 6)
+#define QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE    (1 << 7)
 
 struct quadd_comm_cap {
        u32     pmu:1,