oprofile: minimally working
authorRonald G. Minnich <rminnich@google.com>
Thu, 8 May 2014 00:34:24 +0000 (17:34 -0700)
committerRonald G. Minnich <rminnich@google.com>
Thu, 8 May 2014 00:34:24 +0000 (17:34 -0700)
We don't have on/off control; that's next.

You can echo something > '#K/kpoprofile' and it will go into
the buffer. You can than cat that file. It's a good way to test.
It works.

Need to get the programs going, see if they work and, if so,
enable the rest of the bits. Probably will implement the real
command interface too.

But, sigh. Will probably have to implement all the hokey oprofile
single-value-for-file files, just for compatibility with the
tools. Oh, yuck.

Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/drivers/dev/kprof.c
kern/src/oprofile/cpu_buffer.c

index 00f6401..1377b15 100644 (file)
@@ -36,7 +36,7 @@
 #include <pmap.h>
 #include <smp.h>
 #include <ip.h>
-
+#include <oprofile.h>
 
 #define LRES   3               /* log of PC resolution */
 #define CELLSIZE       8       /* sizeof of count cell */
@@ -259,7 +259,8 @@ kprofread(struct chan *c, void *va, long n, int64_t off)
                n = ret;
                break;
        case Kprofoprofileqid:
-               return qread(opq, va, n);
+               n = qread(opq, va, n);
+               break;
        default:
                n = 0;
                break;
@@ -277,6 +278,7 @@ static void kprof_clear(struct kprof *kp)
 static long
 kprofwrite(struct chan *c, void *a, long n, int64_t unused)
 {
+       uintptr_t pc;
        switch((int)(c->qid.path)){
        case Kprofctlqid:
                if(strncmp(a, "startclr", 8) == 0){
@@ -289,8 +291,21 @@ kprofwrite(struct chan *c, void *a, long n, int64_t unused)
                        kprof.time = 0;
                } else if(strncmp(a, "clear", 5) == 0) {
                        kprof_clear(&kprof);
+               }else if(strncmp(a, "opstart", 8) == 0) {
+                       /* maybe have enable/disable for it. */
+               }else if(strncmp(a, "opstop", 6) == 0) {
+               } else  {
+                       error("startclr|start|stop|clear|opstart|opstop");
                }
                break;
+
+               /* The format is a long as text. We strtoul, and jam it into the
+                * trace buffer.
+                */
+       case Kprofoprofileqid:
+               pc = strtoul(a, 0, 0);
+               oprofile_add_trace(pc);
+               break;
        default:
                error(Ebadusefd);
        }
index 5759caf..4871186 100644 (file)
@@ -58,8 +58,9 @@ static inline
 int op_cpu_buffer_add_data(struct op_entry *entry, unsigned long val)
 {
        assert(entry->size >= 0);
-       if (!entry->size)
+       if (!entry->size) {
                return 0;
+       }
        *entry->data = val;
        entry->size--;
        entry->data++;
@@ -78,8 +79,9 @@ static inline
 int op_cpu_buffer_get_data(struct op_entry *entry, unsigned long *val)
 {
        int size = entry->size;
-       if (!size)
+       if (!size) {
                return 0;
+       }
        *val = *entry->data;
        entry->size--;
        entry->data++;
@@ -140,7 +142,7 @@ int alloc_cpu_buffers(void)
                         */
                        b->last_proc = NULL;
                        b->last_is_kernel = -1;
-                       b->tracing = 0;
+                       b->tracing = 1;
                        b->buffer_size = buffer_size;
                        b->sample_received = 0;
                        b->sample_lost_overflow = 0;
@@ -195,8 +197,10 @@ static struct block *op_cpu_buffer_write_reserve(struct op_entry *entry, int siz
 
        b = allocb(sizeof(struct op_sample) +
                   size * sizeof(entry->sample->data[0]));
-       if (!b)
+       if (!b) {
+               printk("%s: fail\n", __func__);
                return NULL;
+       }
        entry->sample = (void *)b->wp;
        entry->size = size;
        entry->data = entry->sample->data;
@@ -221,6 +225,7 @@ op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace,
 
        if (waserror()) {
                poperror();
+               printk("%s: failed\n", __func__);
                return 1;
        }
 
@@ -277,6 +282,7 @@ op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
 
        if (waserror()) {
                poperror();
+               printk("%s: failed\n", __func__);
                return 1;
        }
 
@@ -285,10 +291,9 @@ op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
        sample = entry.sample;
        sample->eip = pc;
        sample->event = event;
-
        qbwrite(opq, b);
        poperror();
-       return 1;
+       return 0;
 }
 
 /*
@@ -353,10 +358,13 @@ __oprofile_add_ext_sample(unsigned long pc, void /*struct pt_regs*/ * const regs
         */
        if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event, proc))
                /* failed */
-               return;
+               {
+                       return;
+               }
 
-       if (!backtrace)
+       if (!backtrace) {
                return;
+       }
 #if 0
        oprofile_begin_trace(cpu_buf);
        oprofile_ops.backtrace(regs, backtrace);
@@ -410,6 +418,7 @@ oprofile_write_reserve(struct op_entry *entry, void /*struct pt_regs*/ * const r
        struct oprofile_cpu_buffer *cpu_buf = &op_cpu_buffer[core_id()];
 
        if (waserror()){
+               printk("%s: failed\n", __func__);
                poperror();
                goto fail;
        }
@@ -436,23 +445,28 @@ fail:
 
 int oprofile_add_data(struct op_entry *entry, unsigned long val)
 {
-       if (!entry->event)
+       if (!entry->event) {
                return 0;
+       }
        return op_cpu_buffer_add_data(entry, val);
 }
 
 int oprofile_add_data64(struct op_entry *entry, uint64_t val)
 {
-       if (!entry->event)
+       if (!entry->event) {
                return 0;
+       }
        if (op_cpu_buffer_get_size(entry) < 2)
                /*
                 * the function returns 0 to indicate a too small
                 * buffer, even if there is some space left
                 */
+               {
+                       return 0;
+               }
+       if (!op_cpu_buffer_add_data(entry, (uint32_t)val)) {
                return 0;
-       if (!op_cpu_buffer_add_data(entry, (uint32_t)val))
-               return 0;
+       }
        return op_cpu_buffer_add_data(entry, (uint32_t)(val >> 32));
 }
 
@@ -474,8 +488,9 @@ void oprofile_add_trace(unsigned long pc)
 {
        struct oprofile_cpu_buffer *cpu_buf = &op_cpu_buffer[core_id()];
 
-       if (!cpu_buf->tracing)
+       if (!cpu_buf->tracing) {
                return;
+       }
 
        /*
         * broken frame can give an eip with the same value as an
@@ -489,6 +504,7 @@ void oprofile_add_trace(unsigned long pc)
 
        return;
 fail:
+       printk("%s: fail. Turning of tracing on cpu %d\n", core_id());
        cpu_buf->tracing = 0;
        cpu_buf->backtrace_aborted++;
        return;