Return bool from reset_alarm_* apis.
[akaros.git] / kern / src / oprofile / cpu_buffer.c
index b28bab9..5036d7a 100644 (file)
 struct oprofile_cpu_buffer *op_cpu_buffer;
 
 /* this one queue is used by #K to get all events. */
-struct queue *opq;
+static struct queue *opq;
 
 /* this is run from core 0 for all cpu buffers. */
 static void wq_sync_buffer(void);
 unsigned long oprofile_cpu_buffer_size = 65536;
-unsigned long oprofile_backtrace_depth = 8;
+unsigned long oprofile_backtrace_depth = 16;
 
 #define DEFAULT_TIMER_EXPIRE (HZ / 10)
 static int work_enabled;
@@ -138,14 +138,13 @@ int alloc_cpu_buffers(void)
         */
        /* what limit? No idea. */
        if (!opq)
-               opq = qopen(1024, Qmsg, NULL, NULL);
+               opq = qopen(1024, 0, NULL, NULL);
        if (!opq)
                goto fail;
 
        /* we *really* don't want to block. Losing data is better. */
        qnoblock(opq, 1);
        if (!op_cpu_buffer) {
-               printk("ALlocate %d bytes\n", sizeof(*op_cpu_buffer) * num_cpus);
                op_cpu_buffer =
                        kzmalloc(sizeof(*op_cpu_buffer) * num_cpus, KMALLOC_WAIT);
                if (!op_cpu_buffer)
@@ -164,7 +163,7 @@ int alloc_cpu_buffers(void)
                        b->cpu = i;
                        b->fullqueue = qopen(1024, Qmsg, NULL, NULL);
                        b->emptyqueue = qopen(1024, Qmsg, NULL, NULL);
-                       qlock_init(&b->mutex);
+                       spinlock_init_irqsave(&b->lock);
                }
        }
 
@@ -228,13 +227,13 @@ static struct block *op_cpu_buffer_write_reserve(struct oprofile_cpu_buffer *cpu
        b = cpu_buf->block;
        /* we might have run out. */
        if ((! b) || (b->lim - b->wp) < size) {
-               if (b)
-                       qbwrite(opq, b);
-               printk("After qbwrite in %s, opq len %d\n", __func__, qlen(opq));
+               if (b){
+                       qibwrite(opq, b);
+               }
                /* For now. Later, we will grab a block off the
                 * emptyblock queue.
                 */
-               cpu_buf->block = b = allocb(oprofile_cpu_buffer_size);
+               cpu_buf->block = b = iallocb(oprofile_cpu_buffer_size);
                if (!b) {
                        printk("%s: fail\n", __func__);
                        //print_func_exit();
@@ -369,13 +368,13 @@ log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
         * this function returns 0 in event of failure.
         * what a cluster.
         */
-       qlock(&cpu_buf->mutex);
+       spin_lock_irqsave(&cpu_buf->lock);
        if (op_add_code(cpu_buf, backtrace, is_kernel, tsk))
                goto fail;
 
        if (op_add_sample(cpu_buf, pc, event))
                goto fail;
-       qunlock(&cpu_buf->mutex);
+       spin_unlock_irqsave(&cpu_buf->lock);
 
        //print_func_exit();
        return 1;
@@ -405,17 +404,17 @@ void oprofile_cpubuf_flushone(int core, int newbuf)
        //print_func_entry();
        struct oprofile_cpu_buffer *cpu_buf;
        cpu_buf = &op_cpu_buffer[core];
-       qlock(&cpu_buf->mutex);
+       spin_lock_irqsave(&cpu_buf->lock);
        if (cpu_buf->block) {
                printk("Core %d has data\n", core);
-               qbwrite(opq, cpu_buf->block);
-               printk("After qbwrite in %s, opq len %d\n", __func__, qlen(opq));
+               qibwrite(opq, cpu_buf->block);
+               printk("After qibwrite in %s, opq len %d\n", __func__, qlen(opq));
        }
        if (newbuf)
-               cpu_buf->block = allocb(oprofile_cpu_buffer_size);
+               cpu_buf->block = iallocb(oprofile_cpu_buffer_size);
        else
                cpu_buf->block = NULL;
-       qunlock(&cpu_buf->mutex);
+       spin_unlock_irqsave(&cpu_buf->lock);
        //print_func_exit();
 }
 
@@ -621,11 +620,12 @@ void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
 
 void oprofile_add_trace(unsigned long pc)
 {
+       if (! op_cpu_buffer)
+               return;
        //print_func_entry();
        struct oprofile_cpu_buffer *cpu_buf = &op_cpu_buffer[core_id()];
 
        if (!cpu_buf->tracing) {
-               printk("%s: not tracing\n", __func__);
                //print_func_exit();
                return;
        }
@@ -636,8 +636,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();
@@ -649,3 +648,113 @@ fail:
        //print_func_exit();
        return;
 }
+
+/* Format for samples:
+ * first word:
+ * high 8 bits is ee, which is an invalid address on amd64. 
+ * next 8 bits is protocol version
+ * next 16 bits is unused, MBZ. Later, we can make it a packet type. 
+ * next 16 bits is core id
+ * next 8 bits is unused
+ * next 8 bits is # PCs following. This should be at least 1, for one EIP.
+ *
+ * second word is time in ns.
+ * 
+ * Third and following words are PCs, there must be at least one of them. 
+ */
+void oprofile_add_backtrace(uintptr_t pc, uintptr_t fp)
+{
+       /* version 1. */
+       uint64_t descriptor = 0xee01ULL<<48;
+       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;
+       }
+
+       struct op_entry entry;
+       struct op_sample *sample;
+       struct block *b;
+       uint64_t event = nsec();
+
+       uintptr_t bt_pcs[oprofile_backtrace_depth];
+
+       int nr_pcs;
+       nr_pcs = backtrace_list(pc, fp, bt_pcs, oprofile_backtrace_depth);
+
+       /* write_reserve always assumes passed-in-size + 2.
+        * backtrace_depth should always be > 0.
+        */
+       b = op_cpu_buffer_write_reserve(cpu_buf, &entry, nr_pcs);
+
+       if (! b)
+               return;
+
+       /* we are changing the sample format, but not the struct
+        * member names yet. Later, assuming this works out.
+        */
+       descriptor |= (core_id() << 16) | nr_pcs;
+       sample = entry.sample;
+       sample->eip = descriptor;
+       sample->event = event;
+       memcpy(sample->data, bt_pcs, sizeof(uintptr_t) * nr_pcs);
+
+       //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;
+}
+
+void oprofile_add_userpc(uintptr_t pc)
+{
+       struct oprofile_cpu_buffer *cpu_buf;
+       uint32_t pcoreid = core_id();
+       struct op_entry entry;
+       struct block *b;
+       uint64_t descriptor = (0xee01ULL << 48) | (pcoreid << 16) | 1;
+
+       if (!op_cpu_buffer)
+               return;
+       cpu_buf = &op_cpu_buffer[pcoreid];
+       if (!cpu_buf->tracing)
+               return;
+       /* write_reserve always assumes passed-in-size + 2.  need room for 1 PC. */
+       b = op_cpu_buffer_write_reserve(cpu_buf, &entry, 1);
+       if (!b)
+               return;
+       entry.sample->eip = descriptor;
+       entry.sample->event = nsec();
+       /* entry.sample->data == entry.data */
+       assert(entry.sample->data == entry.data);
+       *entry.sample->data = pc;
+}
+
+int
+oproflen(void)
+{
+       return qlen(opq);
+}
+
+/* return # bytes read, or 0 if profiling is off, or block if profiling on and no data.
+ */
+int
+oprofread(void *va, int n)
+{
+       int len = qlen(opq);
+       struct oprofile_cpu_buffer *cpu_buf = &op_cpu_buffer[core_id()];
+       if (len == 0) {
+               if (cpu_buf->tracing == 0)
+                       return 0;
+       }
+
+       len = qread(opq, va, n);
+       return len;
+}