oprofile
authorRonald G. Minnich <rminnich@google.com>
Fri, 23 May 2014 22:18:18 +0000 (15:18 -0700)
committerRonald G. Minnich <rminnich@google.com>
Fri, 23 May 2014 22:18:18 +0000 (15:18 -0700)
The oprofile tools are pretty hardwired to a certain directory structure
that is hard to recreate, and not clearly needed.

Change the output of #K/kpoprofile to the following:
PC
bits 63-4, time in ns; 3-0, number PCs following
[an array of PCs]

I don't think we'll miss the 1 ns precision, because there's no way
we're that accurate. +- 16 ns is fine.

TRACEME now calls oprofile_add_backtrace, which adds the backtrace.

Sadly, we're not seeing any backtrace data, but our Go program finds this output
very easy to digest.

Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/include/kdebug.h
kern/include/oprofile.h
kern/src/oprofile/cpu_buffer.c

index 51af8f2..9c7143e 100644 (file)
@@ -34,6 +34,6 @@ void pahexdump(uintptr_t pa, int length);
 
 /* circular shit... */
 void oprofile_add_trace(unsigned long pc);
-#define TRACEME() oprofile_add_trace(read_pc())
+#define TRACEME() oprofile_add_backtrace(read_bp())
 
 #endif /* ROS_KERN_KDEBUG_H */
index 914bd84..a650201 100644 (file)
@@ -105,6 +105,7 @@ void oprofile_add_ext_hw_sample(unsigned long pc, /*struct pt_regs*/void * const
 /* Use this instead when the PC value is not from the regs. Doesn't
  * backtrace. */
 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event);
+void oprofile_add_backtrace(uintptr_t ebp);
 
 /* add a backtrace entry, to be called from the ->backtrace callback */
 void oprofile_add_trace(unsigned long eip);
index 32bee6c..225149a 100644 (file)
@@ -637,7 +637,7 @@ void oprofile_add_trace(unsigned long pc)
         */
        if (pc == ESCAPE_CODE)
                goto fail;
-       if (op_add_sample(cpu_buf, pc, nsec()))
+       if (op_add_sample(cpu_buf, pc, nsec()&~0xf))
                goto fail;
 
        //print_func_exit();
@@ -650,6 +650,62 @@ fail:
        return;
 }
 
+/* non standard format. Sorry.
+ * pc
+ * event -- bits 63-4 are time in ns. Bit 3-0 are the number of words that
+ * follow.
+ * And then those words. This is so our Go tool can easily create
+ * a pprof-format file for go pprof.
+ */
+void oprofile_add_backtrace(uintptr_t ebp)
+{
+       if (! op_cpu_buffer)
+               return;
+       //print_func_entry();
+       struct oprofile_cpu_buffer *cpu_buf = &op_cpu_buffer[core_id()];
+
+       if (!cpu_buf->tracing) {
+               //print_func_exit();
+               return;
+       }
+
+       uintptr_t eip;
+
+       /* retaddr is right above ebp on the stack.  we subtract an additional 1 to
+        * make sure the eip we get is actually in the function that called us.
+        * i had a couple cases early on where call was the last instruction in a
+        * function, and simply reading the retaddr would point into another
+        * function (the next one in the object) */
+       eip = *(uintptr_t*)(ebp + sizeof(uintptr_t)) - 1;
+       /* jump back a frame (out of backtrace) */
+       ebp = *(uintptr_t *)ebp;
+
+       struct op_entry entry;
+       struct op_sample *sample;
+       struct block *b;
+       uint64_t event = nsec() & ~0xf;
+
+       b = op_cpu_buffer_write_reserve(cpu_buf, &entry, oprofile_backtrace_depth);
+
+       if (! b)
+               return;
+
+       sample = entry.sample;
+       sample->eip = eip;
+       sample->event = event | oprofile_backtrace_depth;
+       /* later, we should skip the first entry because it replicates eip. */
+       backtrace_list(eip, (uintptr_t)ebp, (uintptr_t *)sample->data, oprofile_backtrace_depth);
+
+       //print_func_exit();
+       return;
+fail:
+       printk("%s: fail. Turning of tracing on cpu %d\n", core_id());
+       cpu_buf->tracing = 0;
+       cpu_buf->backtrace_aborted++;
+       //print_func_exit();
+       return;
+}
+
 int
 oproflen(void)
 {