]> xenbits.xensource.com Git - people/royger/linux-2.6.18-xen.git/commitdiff
xenoprofile: Add IBS support
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 2 Aug 2010 10:02:18 +0000 (11:02 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 2 Aug 2010 10:02:18 +0000 (11:02 +0100)
Add IBS support for AMD family 10h processors. The major
implementation is derived from latest Linux. Two hypercalls are added,
which is necessary for IBS feature detection and user mode parameter
read.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
arch/i386/oprofile/op_counter.h
arch/i386/oprofile/xenoprof.c
drivers/oprofile/buffer_sync.c
drivers/oprofile/cpu_buffer.c
drivers/oprofile/event_buffer.h
drivers/oprofile/oprofile_files.c
include/xen/interface/xenoprof.h

index 2880b15c46752e0d14e35a825ebe30d7a6c2f7d3..11e9c0088480110e45f19e4f4cb17d94f7cf48c7 100644 (file)
@@ -26,4 +26,15 @@ struct op_counter_config {
 
 extern struct op_counter_config counter_config[];
 
+/* AMD IBS configuration */
+struct op_ibs_config {
+    unsigned long op_enabled;
+    unsigned long fetch_enabled;
+    unsigned long max_cnt_fetch;
+    unsigned long max_cnt_op;
+    unsigned long rand_en;
+    unsigned long dispatched_ops;
+};
+
+extern struct op_ibs_config ibs_config;
 #endif /* OP_COUNTER_H */
index cb6ae1e38c67e8910251b2b4a720bb7bfdb48c49..734188669efee5c0c90dd0d18409baa4da703cc8 100644 (file)
@@ -27,6 +27,7 @@
 #include "op_counter.h"
 
 static unsigned int num_events = 0;
+static int ibs_caps = 0;
 
 void __init xenoprof_arch_init_counter(struct xenoprof_init *init)
 {
@@ -43,6 +44,7 @@ void xenoprof_arch_counter(void)
 {
        int i;
        struct xenoprof_counter counter;
+       struct xenoprof_ibs_counter ibs_counter;
 
        for (i=0; i<num_events; i++) {
                counter.ind       = i;
@@ -55,6 +57,17 @@ void xenoprof_arch_counter(void)
                WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_counter,
                                               &counter));
        }
+
+       if (ibs_caps) {
+               ibs_counter.op_enabled = ibs_config.op_enabled;
+               ibs_counter.fetch_enabled = ibs_config.fetch_enabled;
+               ibs_counter.max_cnt_fetch = ibs_config.max_cnt_fetch;
+               ibs_counter.max_cnt_op = ibs_config.max_cnt_op;
+               ibs_counter.rand_en = ibs_config.rand_en;
+               ibs_counter.dispatched_ops = ibs_config.dispatched_ops;
+               WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_ibs_counter,
+                               &ibs_counter));
+       }
 }
 
 void xenoprof_arch_start(void) 
@@ -140,13 +153,16 @@ out:
 }
 
 struct op_counter_config counter_config[OP_MAX_COUNTER];
+struct op_ibs_config ibs_config;
+
+#define IBS_CAPS_OPCNT          (1LL<<4)
 
 int xenoprof_create_files(struct super_block * sb, struct dentry * root)
 {
        unsigned int i;
+       struct dentry * dir;
 
        for (i = 0; i < num_events; ++i) {
-               struct dentry * dir;
                char buf[2];
  
                snprintf(buf, 2, "%d", i);
@@ -165,6 +181,35 @@ int xenoprof_create_files(struct super_block * sb, struct dentry * root)
                                        &counter_config[i].user);
        }
 
+       /* AMD IBS support */
+       ibs_caps = HYPERVISOR_xenoprof_op(XENOPROF_get_ibs_caps, NULL);
+       if (!ibs_caps)
+               return 0;
+
+       /* setup some reasonable defaults */
+       ibs_config.max_cnt_fetch = 250000;
+       ibs_config.fetch_enabled = 0;
+       ibs_config.max_cnt_op = 250000;
+       ibs_config.op_enabled = 0;
+       ibs_config.dispatched_ops = 0;
+
+       dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
+       oprofilefs_create_ulong(sb, dir, "enable",
+                               &ibs_config.fetch_enabled);
+       oprofilefs_create_ulong(sb, dir, "max_count",
+                               &ibs_config.max_cnt_fetch);
+       oprofilefs_create_ulong(sb, dir, "rand_enable",
+                               &ibs_config.rand_en);
+
+       dir = oprofilefs_mkdir(sb, root, "ibs_op");
+       oprofilefs_create_ulong(sb, dir, "enable",
+                               &ibs_config.op_enabled);
+       oprofilefs_create_ulong(sb, dir, "max_count",
+                               &ibs_config.max_cnt_op);
+       if (ibs_caps & IBS_CAPS_OPCNT)
+               oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+                               &ibs_config.dispatched_ops);
+
        return 0;
 }
 
index 1b30909d92f52e5c9374821b39a1a7b0a233c989..ec3ef0e073f0c30558edfa4e9e8c5a97e7b4f367 100644 (file)
@@ -498,6 +498,67 @@ static void mark_done(int cpu)
        cpus_clear(marked_cpus);
 }
 
+/* Add IBS samples into event buffer */
+#define IBS_FETCH_SIZE 8
+#define IBS_OP_SIZE            14
+
+static inline struct
+op_sample * get_next_slot(struct oprofile_cpu_buffer * cpu_buf, int next)
+{
+       int pos;
+       pos = cpu_buf->tail_pos + next;
+       if (pos >= cpu_buf->buffer_size)
+               pos = pos - cpu_buf->buffer_size;
+
+       return &cpu_buf->buffer[pos];
+}
+
+static int add_ibs_data(int cpu, struct mm_struct *mm, int cpu_mode)
+{
+       struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu];
+       struct op_sample * s;
+
+       unsigned long cookie;
+       off_t offset;
+       int size, i, code;
+
+       s = get_next_slot(cpu_buf, 1);
+
+       if (s->eip == IBS_FETCH_CODE)
+               size = IBS_FETCH_SIZE;
+       else if (s->eip == IBS_OP_CODE)
+               size = IBS_OP_SIZE;
+       else
+               return 0;
+
+       code = s->eip;
+       s = get_next_slot(cpu_buf, 2);
+
+       if (mm)
+       {
+               cookie = lookup_dcookie(mm, s->eip, &offset);
+               if (cookie != last_cookie) {
+               add_cookie_switch(cookie);
+               last_cookie = cookie;
+               }
+       }
+       else {
+               offset=s->eip;
+       }
+       add_event_entry(ESCAPE_CODE);
+       add_event_entry(code);
+       add_event_entry(offset);
+
+       /* The first 3 slots are ESCAPE_CODE, code and offset,
+       so here we start from slot 4 */
+
+       for (i = 3; i <= size; ++i) {
+               s = get_next_slot(cpu_buf, i);
+               add_event_entry(s->eip);
+       }
+
+       return size;
+}
 
 /* FIXME: this is not sufficient if we implement syscall barrier backtrace
  * traversal, the code switch to sb_sample_start at first kernel enter/exit
@@ -527,6 +588,7 @@ void sync_buffer(int cpu)
        sync_buffer_state state = sb_buffer_start;
        unsigned long available;
        int domain_switch = 0;
+       int is_ibs_sample = 0;
 
        mutex_lock(&buffer_mutex);
  
@@ -568,12 +630,14 @@ void sync_buffer(int cpu)
                                        cookie = get_exec_dcookie(mm);
                                add_user_ctx_switch(new, cookie);
                        }
+                       is_ibs_sample = add_ibs_data(cpu, mm, cpu_mode);
+
                } else {
                        if (domain_switch) {
                                cpu_current_domain[cpu] = s->eip;
                                add_domain_switch(s->eip);
                                domain_switch = 0;
-                       } else {
+                       } else if (!is_ibs_sample) {
                                if (cpu_current_domain[cpu] !=
                                    COORDINATOR_DOMAIN) {
                                        add_sample_entry(s->eip, s->event);
index 58a9c18bb4756af1a608692048cbebf088d6efa6..7c6deb5ba3c7e3f2a1b6a6f3605c0d05b5f57306 100644 (file)
@@ -201,7 +201,10 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
                cpu_buf->last_task = task;
                add_code(cpu_buf, (unsigned long)task);
        }
+
+       if (pc == IBS_FETCH_CODE || pc == IBS_OP_CODE)
+               add_code(cpu_buf, cpu_mode);
+
        add_sample(cpu_buf, pc, event);
        return 1;
 }
index 6a8878866c84508291831b702e7aade940254157..270868b90d36e02b6a5dc551d5685d0b804b6553 100644 (file)
@@ -36,6 +36,8 @@ void wake_up_buffer_waiter(void);
 #define TRACE_END_CODE                 9
 #define XEN_ENTER_SWITCH_CODE          10
 #define DOMAIN_SWITCH_CODE             11
+#define IBS_FETCH_CODE                 13
+#define IBS_OP_CODE                            14
  
 #define INVALID_COOKIE ~0UL
 #define NO_COOKIE 0UL
index 6719420451c622fc2c50fb3b694028b4d8c58abd..bd3afc05a682ed2ddfcd800a286afd7ee599789f 100644 (file)
@@ -21,7 +21,7 @@
 #include "oprof.h"
 
 unsigned long fs_buffer_size = 131072;
-unsigned long fs_cpu_buffer_size = 8192;
+unsigned long fs_cpu_buffer_size = 131072;
 unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
 
 static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
index 183078d8db8c7deeeebf87864001482d53698be1..451b8677bac8308d61583dc11a3dc6a2afe783c8 100644 (file)
 #define XENOPROF_shutdown           13
 #define XENOPROF_get_buffer         14
 #define XENOPROF_set_backtrace      15
-#define XENOPROF_last_op            15
+/* AMD IBS support */
+#define XENOPROF_get_ibs_caps       16
+#define XENOPROF_ibs_counter        17
+
+#define XENOPROF_last_op            17
 
 #define MAX_OPROF_EVENTS    32
 #define MAX_OPROF_DOMAINS   25
@@ -124,7 +128,16 @@ typedef struct xenoprof_passive {
 } xenoprof_passive_t;
 DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t);
 
-
+struct xenoprof_ibs_counter {
+    uint64_t op_enabled;
+    uint64_t fetch_enabled;
+    uint64_t max_cnt_fetch;
+    uint64_t max_cnt_op;
+    uint64_t rand_en;
+    uint64_t dispatched_ops;
+};
+typedef struct xenoprof_ibs_counter xenoprof_ibs_counter_t;
+DEFINE_XEN_GUEST_HANDLE(xenoprof_ibs_counter_t);
 #endif /* __XEN_PUBLIC_XENOPROF_H__ */
 
 /*