Adds a pcpui trace buffer for generic events
authorBarret Rhoden <brho@cs.berkeley.edu>
Sat, 27 Jul 2013 00:09:51 +0000 (17:09 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 27 Jul 2013 00:09:51 +0000 (17:09 -0700)
Users pick the next available type and provide a handler.  You can run
all the handlers or reset the trace ring from the kernel monitor (e.g.
trace pcpui, trace pcpui-reset).

All users should use the same access method (racy, no overwrite).  If
some subsystem uses overwrite, they'll end up starving the
non-overwriters.

kern/include/smp.h
kern/src/monitor.c
kern/src/smp.c

index 501ada5..2da6fe9 100644 (file)
@@ -17,6 +17,7 @@
 #include <process.h>
 #include <syscall.h>
 #include <alarm.h>
+#include <trace.h>
 
 #ifdef __SHARC__
 typedef sharC_env_t;
@@ -40,6 +41,7 @@ struct per_cpu_info {
        struct kthread *spare;          /* useful when restarting */
        struct timer_chain tchain;      /* for the per-core alarm */
        unsigned int lock_depth;
+       struct trace_ring traces;
 
 #ifdef __SHARC__
        // held spin-locks. this will have to go elsewhere if multiple kernel
@@ -88,4 +90,24 @@ int smp_call_function_single(uint32_t dest, poly_isr_t handler, TV(t) data,
                              handler_wrapper_t** wait_wrapper);
 int smp_call_wait(handler_wrapper_t*SAFE wrapper);
 
-#endif /* !ROS_INC_SMP_H */
+/* PCPUI Trace Rings: */
+struct pcpu_trace_event {
+       int                                                     type;
+       int                                                     arg0;
+       uint64_t                                        arg1;
+};
+
+/* If you want to add a type, use the next available number, increment NR_TYPES,
+ * use your own macro, and provide a handler.  Add your handler to
+ * pcpui_tr_handlers in smp.c. */
+#define PCPUI_TR_TYPE_NULL             0
+#define PCPUI_NR_TYPES                 1
+
+/* Run the handlers for all events in a pcpui ring.  Can run on all cores, or
+ * just one core.  'type' selects which event type is handled (0 for all). */
+void pcpui_tr_foreach(int coreid, int type);
+void pcpui_tr_foreach_all(int type);
+void pcpui_tr_reset_all(void);
+void pcpui_tr_reset_and_clear_all(void);
+
+#endif /* ROS_INC_SMP_H */
index 463ace6..fe3bb50 100644 (file)
@@ -642,6 +642,8 @@ int mon_trace(int argc, char **argv, struct hw_trapframe *hw_tf)
                printk("\tsyscall start [silent] [pid]: starts tracing\n");
                printk("\tsyscall stop: stops tracing, prints if it was silent\n");
                printk("\tcoretf COREID: cause the other core to print its TF (NMI)\n");
+               printk("\tpcpui [type [coreid]]: runs pcpui trace ring handlers\n");
+               printk("\tpcpui-reset [noclear]: resets/clears pcpui trace ring\n");
                return 1;
        }
        if (!strcmp(argv[1], "syscall")) {
@@ -685,6 +687,27 @@ int mon_trace(int argc, char **argv, struct hw_trapframe *hw_tf)
                }
                send_nmi(core);
                udelay(1000000);
+       } else if (!strcmp(argv[1], "pcpui")) {
+               int pcpui_type, pcpui_coreid;
+               if (argc >= 3)
+                       pcpui_type = strtol(argv[2], 0, 0);
+               else
+                       pcpui_type = 0;
+               printk("\nRunning PCPUI Trace Ring handlers for type %d\n", pcpui_type);
+               if (argc >= 4) {
+                       pcpui_coreid = strtol(argv[3], 0, 0); 
+                       pcpui_tr_foreach(pcpui_coreid, pcpui_type);
+               } else {
+                       pcpui_tr_foreach_all(pcpui_type);
+               }
+       } else if (!strcmp(argv[1], "pcpui-reset")) {
+               if (argc >= 3) {
+                       printk("\nResetting all PCPUI Trace Rings\n");
+                       pcpui_tr_reset_all();
+               } else {
+                       printk("\nResetting and clearing all PCPUI Trace Rings\n");
+                       pcpui_tr_reset_and_clear_all();
+               }
        } else if (!strcmp(argv[1], "opt2")) {
                if (argc != 3) {
                        printk("ERRRRRRRRRR.\n");
index 3586289..2560e5c 100644 (file)
@@ -19,6 +19,9 @@
 #include <process.h>
 #include <schedule.h>
 #include <trap.h>
+#include <trace.h>
+#include <kdebug.h>
+#include <kmalloc.h>
 
 struct per_cpu_info per_cpu_info[MAX_NUM_CPUS];
 
@@ -85,6 +88,8 @@ void smp_idle(void)
 void smp_percpu_init(void)
 {
        uint32_t coreid = core_id();
+       struct per_cpu_info *pcpui = &per_cpu_info[coreid];
+       void *trace_buf;
        /* Don't initialize __ctx_depth here, since it is already 1 (at least on
         * x86), since this runs in irq context. */
        /* Do this first */
@@ -102,4 +107,57 @@ void smp_percpu_init(void)
        uintptr_t *poison = (uintptr_t*)ROUNDDOWN(get_stack_top() - 1, PGSIZE);
        *poison = 0xdeadbeef;
 #endif /* CONFIG_KTHREAD_POISON */
+       /* Init generic tracing ring */
+       trace_buf = kpage_alloc_addr();
+       assert(trace_buf);
+       trace_ring_init(&pcpui->traces, trace_buf, PGSIZE,
+                       sizeof(struct pcpu_trace_event));
+}
+
+/* PCPUI Trace Rings: */
+
+/* Add specific trace handlers here: */
+trace_handler_t pcpui_tr_handlers[PCPUI_NR_TYPES] = {
+                                  0,
+                                  };
+
+/* Generic handler for the pcpui ring.  Will switch out to the appropriate
+ * type's handler */
+static void pcpui_trace_fn(void *event, void *data)
+{
+       struct pcpu_trace_event *te = (struct pcpu_trace_event*)event;
+       int desired_type = (int)(long)data;
+       if (te->type >= PCPUI_NR_TYPES)
+               printk("Bad trace type %d\n", te->type);
+       /* desired_type == 0 means all types */
+       if (desired_type && desired_type != te->type)
+               return;
+       if (pcpui_tr_handlers[te->type])
+               pcpui_tr_handlers[te->type](event, data);
+}
+
+void pcpui_tr_foreach(int coreid, int type)
+{
+       struct trace_ring *tr = &per_cpu_info[coreid].traces;
+       assert(tr);
+       printk("\n\nTrace Ring on Core %d\n--------------\n", coreid);
+       trace_ring_foreach(tr, pcpui_trace_fn, (void*)(long)type);
+}
+
+void pcpui_tr_foreach_all(int type)
+{
+       for (int i = 0; i < num_cpus; i++)
+               pcpui_tr_foreach(i, type);
+}
+
+void pcpui_tr_reset_all(void)
+{
+       for (int i = 0; i < num_cpus; i++)
+               trace_ring_reset(&per_cpu_info[i].traces);
+}
+
+void pcpui_tr_reset_and_clear_all(void)
+{
+       for (int i = 0; i < num_cpus; i++)
+               trace_ring_reset_and_clear(&per_cpu_info[i].traces);
 }