Adding initial support for performance counters.
authorDavid Zhu <yuzhu@cs.berkeley.edu>
Mon, 3 May 2010 01:53:54 +0000 (18:53 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:47 +0000 (17:35 -0700)
The kernel sets up the performance counter specifically for OSDI.
It also changes cr4 to allow user level to read performance counters.
User can read pmc to obtain the relevant counter data.

kern/arch/i686/Makefrag
kern/arch/i686/init.c
kern/arch/i686/perfmon.c [new file with mode: 0644]
kern/arch/i686/perfmon.h [new file with mode: 0644]
kern/arch/i686/smp_boot.c
user/include/i686/arch.h

index 4f1dd93..41cbe7e 100644 (file)
@@ -35,5 +35,6 @@ KERN_ARCH_SRCFILES := $(KERN_ARCH_SRC_DIR)/entry.S \
                       $(KERN_ARCH_SRC_DIR)/nic_common.c \
                       $(KERN_ARCH_SRC_DIR)/init.c \
                       $(KERN_ARCH_SRC_DIR)/env.c \
-                      $(KERN_ARCH_SRC_DIR)/frontend.c
+                      $(KERN_ARCH_SRC_DIR)/frontend.c \
+                      $(KERN_ARCH_SRC_DIR)/perfmon.c
 
index ff650bf..3f5b1a4 100644 (file)
@@ -13,6 +13,8 @@
 #include <arch/pci.h>
 #include <arch/ioapic.h>
 #include <arch/console.h>
+#include <arch/perfmon.h>
+
 #include <monitor.h>
 
 void arch_init()
@@ -53,6 +55,8 @@ void arch_init()
        #endif // __CONFIG_SINGLE_CORE__
        #endif // __CONFIG_NETWORKING__
 
+       perfmon_init();
+               
 #ifdef __CONFIG_MONITOR_ON_INT__
        /* Handler to read a char from the interrupt source and call the monitor.
         * Need to read the character so the device will send another interrupt.
diff --git a/kern/arch/i686/perfmon.c b/kern/arch/i686/perfmon.c
new file mode 100644 (file)
index 0000000..ad5ad8b
--- /dev/null
@@ -0,0 +1,19 @@
+#include <arch/perfmon.h> 
+
+
+static void setup_counter(int index, uint8_t mask, uint8_t event) {
+       //just a magic number for now to indicate the most common case
+       uint32_t os_user_enabled = 0x43;
+       write_msr(IA32_PERFEVTSEL_BASE + index, (os_user_enabled<<16 | mask<<8 | event));
+}
+
+void perfmon_init() {
+#ifdef __CONFIG_OSDI__
+       //setting up to collect cache miss behavior specifically for OSDI
+       setup_counter(0, LLCACHE_REF_MASK, LLCACHE_EVENT);
+       setup_counter(1, LLCACHE_MISS_MASK, LLCACHE_EVENT);
+
+  //enable user level access to the performance counters
+  lcr4(rcr4() | CR4_PCE);
+#endif
+}
diff --git a/kern/arch/i686/perfmon.h b/kern/arch/i686/perfmon.h
new file mode 100644 (file)
index 0000000..c03c59d
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef ROS_INC_PERFMON_H
+#define ROS_INC_PERFMON_H
+#include <ros/common.h>
+#include <arch/x86.h>
+
+#define IA32_PMC_BASE 0xC1
+#define IA32_PERFEVTSEL_BASE 0x186
+
+#define LLCACHE_EVENT 0x2E
+#define LLCACHE_MISS_MASK 0x41
+#define LLCACHE_REF_MASK 0x4F
+#define ENABLE_PERFCTR 0x00400000
+#define DISABLE_PERFCTR 0xFFAFFFFF
+
+
+static __inline uint64_t
+read_pmc(void)
+{
+    uint64_t pmc;
+    __asm __volatile("rdpmc" : "=A" (pmc));
+    return pmc;
+}
+
+void perfmon_init();
+
+#endif /* ROS_INC_PERFMON_H */
index 92c9954..ef7ee3c 100644 (file)
@@ -15,6 +15,7 @@
 #include <arch/console.h>
 #include <arch/apic.h>
 #include <arch/bitmask.h>
+#include <arch/perfmon.h>
 #include <timing.h>
 
 #include <atomic.h>
@@ -327,4 +328,6 @@ void smp_percpu_init(void)
         * EXPER_TRADPROC, in line with what sparc does. */
        set_core_timer(TIMER_uSEC);
 #endif
+
+  perfmon_init();
 }
index e5ade85..ee7ad75 100644 (file)
@@ -39,4 +39,14 @@ cpu_relax(void)
        asm volatile("pause" : : : "memory");
 }
 
+static __inline uint64_t                                                                             
+read_pmc(uint32_t index)
+{                                                                                                    
+    uint64_t pmc;
+
+    __asm __volatile("rdpmc" : "=A" (pmc) : "c" (index)); 
+    return pmc;                                                                                      
+}
+
+
 #endif /* PARLIB_ARCH_H */