Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 159969 Details for
Bug 245582
[RHEL4]: Add xenoprof support to the i386 and x86_64 PV kernels
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Very rough first patch for xenoprof support
linux-2.6.9-xenoprof.patch (text/plain), 30.97 KB, created by
Chris Lalancette
on 2007-07-25 18:27:07 UTC
(
hide
)
Description:
Very rough first patch for xenoprof support
Filename:
MIME Type:
Creator:
Chris Lalancette
Created:
2007-07-25 18:27:07 UTC
Size:
30.97 KB
patch
obsolete
>diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/i386/Kconfig /root/linux-2.6.9/arch/i386/Kconfig >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/i386/Kconfig 2007-07-17 13:09:56.000000000 -0400 >+++ /root/linux-2.6.9/arch/i386/Kconfig 2007-07-17 12:56:40.000000000 -0400 >@@ -1295,9 +1295,7 @@ source "drivers/Kconfig" > > source "fs/Kconfig" > >-if !X86_XEN > source "arch/i386/oprofile/Kconfig" >-endif > > source "arch/i386/Kconfig.debug" > >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/i386/oprofile/Makefile /root/linux-2.6.9/arch/i386/oprofile/Makefile >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/i386/oprofile/Makefile 2004-10-18 17:55:06.000000000 -0400 >+++ /root/linux-2.6.9/arch/i386/oprofile/Makefile 2007-07-17 12:56:40.000000000 -0400 >@@ -6,7 +6,11 @@ DRIVER_OBJS = $(addprefix ../../../drive > oprofilefs.o oprofile_stats.o \ > timer_int.o ) > >+ifdef CONFIG_XEN >+oprofile-y := $(DRIVER_OBJS) xenoprof.o >+else > oprofile-y := $(DRIVER_OBJS) init.o > oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \ > op_model_ppro.o op_model_p4.o > oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o >+endif >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/i386/oprofile/xenoprof.c /root/linux-2.6.9/arch/i386/oprofile/xenoprof.c >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/i386/oprofile/xenoprof.c 1969-12-31 19:00:00.000000000 -0500 >+++ /root/linux-2.6.9/arch/i386/oprofile/xenoprof.c 2007-07-17 13:04:53.000000000 -0400 >@@ -0,0 +1,582 @@ >+/** >+ * @file xenoprof.c >+ * >+ * @remark Copyright 2002 OProfile authors >+ * @remark Read the file COPYING >+ * >+ * @author John Levon <levon@movementarian.org> >+ * >+ * Modified by Aravind Menon and Jose Renato Santos for Xen >+ * These modifications are: >+ * Copyright (C) 2005 Hewlett-Packard Co. >+ */ >+ >+#include <linux/init.h> >+#include <linux/notifier.h> >+#include <linux/smp.h> >+#include <linux/oprofile.h> >+#include <linux/sysdev.h> >+#include <linux/slab.h> >+#include <linux/interrupt.h> >+#include <linux/vmalloc.h> >+#include <asm/nmi.h> >+#include <asm/msr.h> >+#include <asm/apic.h> >+#include <asm/pgtable.h> >+#include <xen/evtchn.h> >+#include "op_counter.h" >+ >+#include <xen/driver_util.h> >+#include <xen/interface/xen.h> >+#include <xen/interface/xenoprof.h> >+#include <../../../drivers/oprofile/cpu_buffer.h> >+#include <../../../drivers/oprofile/event_buffer.h> >+ >+#define MAX_XENOPROF_SAMPLES 16 >+ >+static int xenoprof_start(void); >+static void xenoprof_stop(void); >+ >+static int xenoprof_enabled = 0; >+static unsigned int num_events = 0; >+static int is_primary = 0; >+static int active_defined; >+ >+/* sample buffers shared with Xen */ >+xenoprof_buf_t * xenoprof_buf[MAX_VIRT_CPUS]; >+/* Shared buffer area */ >+char * shared_buffer = NULL; >+/* Number of buffers in shared area (one per VCPU) */ >+int nbuf; >+/* Mappings of VIRQ_XENOPROF to irq number (per cpu) */ >+int ovf_irq[NR_CPUS]; >+/* cpu model type string - copied from Xen memory space on XENOPROF_init command */ >+char cpu_type[XENOPROF_CPU_TYPE_SIZE]; >+ >+/* Passive sample buffers shared with Xen */ >+xenoprof_buf_t *p_xenoprof_buf[MAX_OPROF_DOMAINS][MAX_VIRT_CPUS]; >+/* Passive shared buffer area */ >+char *p_shared_buffer[MAX_OPROF_DOMAINS]; >+ >+#ifdef CONFIG_PM >+ >+static int xenoprof_suspend(struct sys_device * dev, pm_message_t state) >+{ >+ if (xenoprof_enabled == 1) >+ xenoprof_stop(); >+ return 0; >+} >+ >+ >+static int xenoprof_resume(struct sys_device * dev) >+{ >+ if (xenoprof_enabled == 1) >+ xenoprof_start(); >+ return 0; >+} >+ >+ >+static struct sysdev_class oprofile_sysclass = { >+ set_kset_name("oprofile"), >+ .resume = xenoprof_resume, >+ .suspend = xenoprof_suspend >+}; >+ >+ >+static struct sys_device device_oprofile = { >+ .id = 0, >+ .cls = &oprofile_sysclass, >+}; >+ >+ >+static int __init init_driverfs(void) >+{ >+ int error; >+ if (!(error = sysdev_class_register(&oprofile_sysclass))) >+ error = sysdev_register(&device_oprofile); >+ return error; >+} >+ >+ >+static void __exit exit_driverfs(void) >+{ >+ sysdev_unregister(&device_oprofile); >+ sysdev_class_unregister(&oprofile_sysclass); >+} >+ >+#else >+#define init_driverfs() do { } while (0) >+#define exit_driverfs() do { } while (0) >+#endif /* CONFIG_PM */ >+ >+unsigned long long oprofile_samples = 0; >+unsigned long long p_oprofile_samples = 0; >+ >+unsigned int pdomains; >+struct xenoprof_passive passive_domains[MAX_OPROF_DOMAINS]; >+ >+static void xenoprof_add_pc(xenoprof_buf_t *buf, int is_passive) >+{ >+ int head, tail, size; >+ >+ head = buf->event_head; >+ tail = buf->event_tail; >+ size = buf->event_size; >+ >+ if (tail > head) { >+ while (tail < size) { >+ oprofile_add_pc(buf->event_log[tail].eip, >+ buf->event_log[tail].mode, >+ buf->event_log[tail].event); >+ if (!is_passive) >+ oprofile_samples++; >+ else >+ p_oprofile_samples++; >+ tail++; >+ } >+ tail = 0; >+ } >+ while (tail < head) { >+ oprofile_add_pc(buf->event_log[tail].eip, >+ buf->event_log[tail].mode, >+ buf->event_log[tail].event); >+ if (!is_passive) >+ oprofile_samples++; >+ else >+ p_oprofile_samples++; >+ tail++; >+ } >+ >+ buf->event_tail = tail; >+} >+ >+static void xenoprof_handle_passive(void) >+{ >+ int i, j; >+ int flag_domain, flag_switch = 0; >+ >+ for (i = 0; i < pdomains; i++) { >+ flag_domain = 0; >+ for (j = 0; j < passive_domains[i].nbuf; j++) { >+ xenoprof_buf_t *buf = p_xenoprof_buf[i][j]; >+ if (buf->event_head == buf->event_tail) >+ continue; >+ if (!flag_domain) { >+ if (!oprofile_add_domain_switch(passive_domains[i]. >+ domain_id)) >+ goto done; >+ flag_domain = 1; >+ } >+ xenoprof_add_pc(buf, 1); >+ flag_switch = 1; >+ } >+ } >+done: >+ if (flag_switch) >+ oprofile_add_domain_switch(COORDINATOR_DOMAIN); >+} >+ >+static irqreturn_t >+xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs) >+{ >+ struct xenoprof_buf * buf; >+ int cpu; >+ static unsigned long flag; >+ >+ cpu = smp_processor_id(); >+ buf = xenoprof_buf[cpu]; >+ >+ xenoprof_add_pc(buf, 0); >+ >+ if (is_primary && !test_and_set_bit(0, &flag)) { >+ xenoprof_handle_passive(); >+ smp_mb__before_clear_bit(); >+ clear_bit(0, &flag); >+ } >+ >+ return IRQ_HANDLED; >+} >+ >+ >+static void unbind_virq(void) >+{ >+ int i; >+ >+ for_each_possible_cpu(i) { >+ if (ovf_irq[i] >= 0) { >+ unbind_from_irqhandler(ovf_irq[i], NULL); >+ ovf_irq[i] = -1; >+ } >+ } >+} >+ >+ >+static int bind_virq(void) >+{ >+ int i, result; >+ >+ for_each_possible_cpu(i) { >+ result = bind_virq_to_irqhandler(VIRQ_XENOPROF, >+ i, >+ xenoprof_ovf_interrupt, >+ SA_INTERRUPT, >+ "xenoprof", >+ NULL); >+ >+ if (result < 0) { >+ unbind_virq(); >+ return result; >+ } >+ >+ ovf_irq[i] = result; >+ } >+ >+ return 0; >+} >+ >+ >+static int map_xenoprof_buffer(int max_samples) >+{ >+ struct xenoprof_get_buffer get_buffer; >+ struct xenoprof_buf *buf; >+ int npages, ret, i; >+ struct vm_struct *area; >+ >+ if ( shared_buffer ) >+ return 0; >+ >+ get_buffer.max_samples = max_samples; >+ >+ if ( (ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, &get_buffer)) ) >+ return ret; >+ >+ nbuf = get_buffer.nbuf; >+ npages = (get_buffer.bufsize * nbuf - 1) / PAGE_SIZE + 1; >+ >+ area = alloc_vm_area(npages * PAGE_SIZE); >+ if (area == NULL) >+ return -ENOMEM; >+ >+ if ( (ret = direct_kernel_remap_pfn_range( >+ (unsigned long)area->addr, >+ get_buffer.buf_maddr >> PAGE_SHIFT, >+ npages * PAGE_SIZE, __pgprot(_KERNPG_TABLE), DOMID_SELF)) ) { >+ vunmap(area->addr); >+ return ret; >+ } >+ >+ shared_buffer = area->addr; >+ for (i=0; i< nbuf; i++) { >+ buf = (struct xenoprof_buf*) >+ &shared_buffer[i * get_buffer.bufsize]; >+ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS); >+ xenoprof_buf[buf->vcpu_id] = buf; >+ } >+ >+ return 0; >+} >+ >+ >+static int xenoprof_setup(void) >+{ >+ int ret; >+ int i; >+ >+ if ( (ret = map_xenoprof_buffer(MAX_XENOPROF_SAMPLES)) ) >+ return ret; >+ >+ if ( (ret = bind_virq()) ) >+ return ret; >+ >+ if (is_primary) { >+ struct xenoprof_counter counter; >+ >+ /* Define dom0 as an active domain if not done yet */ >+ if (!active_defined) { >+ domid_t domid; >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL); >+ if (ret) >+ goto err; >+ domid = 0; >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid); >+ if (ret) >+ goto err; >+ active_defined = 1; >+ } >+ >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reserve_counters, NULL); >+ if (ret) >+ goto err; >+ for (i=0; i<num_events; i++) { >+ counter.ind = i; >+ counter.count = (uint64_t)counter_config[i].count; >+ counter.enabled = (uint32_t)counter_config[i].enabled; >+ counter.event = (uint32_t)counter_config[i].event; >+ counter.kernel = (uint32_t)counter_config[i].kernel; >+ counter.user = (uint32_t)counter_config[i].user; >+ counter.unit_mask = (uint64_t)counter_config[i].unit_mask; >+ HYPERVISOR_xenoprof_op(XENOPROF_counter, >+ &counter); >+ } >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_setup_events, NULL); >+ >+ if (ret) >+ goto err; >+ } >+ >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_enable_virq, NULL); >+ if (ret) >+ goto err; >+ >+ xenoprof_enabled = 1; >+ return 0; >+ err: >+ unbind_virq(); >+ return ret; >+} >+ >+ >+static void xenoprof_shutdown(void) >+{ >+ xenoprof_enabled = 0; >+ >+ HYPERVISOR_xenoprof_op(XENOPROF_disable_virq, NULL); >+ >+ if (is_primary) { >+ HYPERVISOR_xenoprof_op(XENOPROF_release_counters, NULL); >+ active_defined = 0; >+ } >+ >+ unbind_virq(); >+ >+} >+ >+ >+static int xenoprof_start(void) >+{ >+ int ret = 0; >+ >+ if (is_primary) >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_start, NULL); >+ >+ return ret; >+} >+ >+ >+static void xenoprof_stop(void) >+{ >+ if (is_primary) >+ HYPERVISOR_xenoprof_op(XENOPROF_stop, NULL); >+} >+ >+ >+int xenoprof_set_active(int * active_domains, >+ unsigned int adomains) >+{ >+ int ret = 0; >+ int i; >+ int set_dom0 = 0; >+ domid_t domid; >+ >+ if (!is_primary) >+ return 0; >+ >+ if (adomains > MAX_OPROF_DOMAINS) >+ return -E2BIG; >+ >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL); >+ if (ret) >+ return ret; >+ >+ for (i=0; i<adomains; i++) { >+ domid = active_domains[i]; >+ if (domid != active_domains[i]) { >+ ret = -EINVAL; >+ goto out; >+ } >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid); >+ if (ret) >+ goto out; >+ if (active_domains[i] == 0) >+ set_dom0 = 1; >+ } >+ /* dom0 must always be active but may not be in the list */ >+ if (!set_dom0) { >+ domid = 0; >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid); >+ } >+ >+out: >+ if (ret) >+ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL); >+ active_defined = !ret; >+ return ret; >+} >+ >+int xenoprof_set_passive(int * p_domains, >+ unsigned int pdoms) >+{ >+ int ret; >+ int i, j; >+ int npages; >+ struct xenoprof_buf *buf; >+ struct vm_struct *area; >+ pgprot_t prot = __pgprot(_KERNPG_TABLE); >+ >+ if (!is_primary) >+ return 0; >+ >+ if (pdoms > MAX_OPROF_DOMAINS) >+ return -E2BIG; >+ >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_passive_list, NULL); >+ if (ret) >+ return ret; >+ >+ for (i = 0; i < pdoms; i++) { >+ passive_domains[i].domain_id = p_domains[i]; >+ passive_domains[i].max_samples = 2048; >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_passive, >+ &passive_domains[i]); >+ if (ret) >+ goto out; >+ >+ npages = (passive_domains[i].bufsize * passive_domains[i].nbuf - 1) / PAGE_SIZE + 1; >+ >+ area = alloc_vm_area(npages * PAGE_SIZE); >+ if (area == NULL) { >+ ret = -ENOMEM; >+ goto out; >+ } >+ >+ ret = direct_kernel_remap_pfn_range( >+ (unsigned long)area->addr, >+ passive_domains[i].buf_maddr >> PAGE_SHIFT, >+ npages * PAGE_SIZE, prot, DOMID_SELF); >+ if (ret) { >+ vunmap(area->addr); >+ goto out; >+ } >+ >+ p_shared_buffer[i] = area->addr; >+ >+ for (j = 0; j < passive_domains[i].nbuf; j++) { >+ buf = (struct xenoprof_buf *) >+ &p_shared_buffer[i][j * passive_domains[i].bufsize]; >+ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS); >+ p_xenoprof_buf[i][buf->vcpu_id] = buf; >+ } >+ >+ } >+ >+ pdomains = pdoms; >+ return 0; >+ >+out: >+ for (j = 0; j < i; j++) { >+ vunmap(p_shared_buffer[j]); >+ p_shared_buffer[j] = NULL; >+ } >+ >+ return ret; >+} >+ >+struct op_counter_config counter_config[OP_MAX_COUNTER]; >+ >+static int xenoprof_create_files(struct super_block * sb, struct dentry * root) >+{ >+ unsigned int i; >+ >+ for (i = 0; i < num_events; ++i) { >+ struct dentry * dir; >+ char buf[2]; >+ >+ snprintf(buf, 2, "%d", i); >+ dir = oprofilefs_mkdir(sb, root, buf); >+ oprofilefs_create_ulong(sb, dir, "enabled", >+ &counter_config[i].enabled); >+ oprofilefs_create_ulong(sb, dir, "event", >+ &counter_config[i].event); >+ oprofilefs_create_ulong(sb, dir, "count", >+ &counter_config[i].count); >+ oprofilefs_create_ulong(sb, dir, "unit_mask", >+ &counter_config[i].unit_mask); >+ oprofilefs_create_ulong(sb, dir, "kernel", >+ &counter_config[i].kernel); >+ oprofilefs_create_ulong(sb, dir, "user", >+ &counter_config[i].user); >+ } >+ >+ return 0; >+} >+ >+ >+struct oprofile_operations xenoprof_ops = { >+ .create_files = xenoprof_create_files, >+ .setup = xenoprof_setup, >+ .shutdown = xenoprof_shutdown, >+ .start = xenoprof_start, >+ .stop = xenoprof_stop >+}; >+ >+ >+/* in order to get driverfs right */ >+static int using_xenoprof; >+ >+int __init oprofile_arch_init(struct oprofile_operations ** ops) >+{ >+ struct xenoprof_init init; >+ int ret, i; >+ >+ ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init); >+ >+ if (!ret) { >+ num_events = init.num_events; >+ is_primary = init.is_primary; >+ >+ /* just in case - make sure we do not overflow event list >+ (i.e. counter_config list) */ >+ if (num_events > OP_MAX_COUNTER) >+ num_events = OP_MAX_COUNTER; >+ >+ /* cpu_type is detected by Xen */ >+ cpu_type[XENOPROF_CPU_TYPE_SIZE-1] = 0; >+ strncpy(cpu_type, init.cpu_type, XENOPROF_CPU_TYPE_SIZE - 1); >+ xenoprof_ops.cpu_type = cpu_type; >+ >+ init_driverfs(); >+ using_xenoprof = 1; >+ *ops = &xenoprof_ops; >+ >+ for (i=0; i<NR_CPUS; i++) >+ ovf_irq[i] = -1; >+ >+ active_defined = 0; >+ } >+ printk(KERN_INFO "oprofile_arch_init: ret %d, events %d, " >+ "is_primary %d\n", ret, num_events, is_primary); >+ return ret; >+} >+ >+ >+void __exit oprofile_arch_exit(void) >+{ >+ int i; >+ >+ if (using_xenoprof) >+ exit_driverfs(); >+ >+ if (shared_buffer) { >+ vunmap(shared_buffer); >+ shared_buffer = NULL; >+ } >+ if (is_primary) { >+ for (i = 0; i < pdomains; i++) >+ if (p_shared_buffer[i]) { >+ vunmap(p_shared_buffer[i]); >+ p_shared_buffer[i] = NULL; >+ } >+ HYPERVISOR_xenoprof_op(XENOPROF_shutdown, NULL); >+ } >+ >+} >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/x86_64/oprofile/Makefile /root/linux-2.6.9/arch/x86_64/oprofile/Makefile >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/arch/x86_64/oprofile/Makefile 2004-10-18 17:53:43.000000000 -0400 >+++ /root/linux-2.6.9/arch/x86_64/oprofile/Makefile 2007-07-17 12:56:40.000000000 -0400 >@@ -11,9 +11,13 @@ DRIVER_OBJS = $(addprefix ../../../drive > oprofilefs.o oprofile_stats.o \ > timer_int.o ) > >+ifdef CONFIG_XEN >+OPROFILE-y := xenoprof.o >+else > OPROFILE-y := init.o > OPROFILE-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o op_model_p4.o \ > op_model_ppro.o > OPROFILE-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o >+endif > > oprofile-y = $(DRIVER_OBJS) $(addprefix ../../i386/oprofile/, $(OPROFILE-y)) >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/buffer_sync.c /root/linux-2.6.9/drivers/oprofile/buffer_sync.c >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/buffer_sync.c 2004-10-18 17:53:45.000000000 -0400 >+++ /root/linux-2.6.9/drivers/oprofile/buffer_sync.c 2007-07-17 12:56:40.000000000 -0400 >@@ -6,6 +6,10 @@ > * > * @author John Levon <levon@movementarian.org> > * >+ * Modified by Aravind Menon for Xen >+ * These modifications are: >+ * Copyright (C) 2005 Hewlett-Packard Co. >+ * > * This is the core of the buffer management. Each > * CPU buffer is processed and entered into the > * global event buffer. Such processing is necessary >@@ -265,13 +269,29 @@ static void add_cpu_switch(int i) > last_cookie = ~0UL; > } > >-static void add_kernel_ctx_switch(unsigned int in_kernel) >+static void add_cpu_mode_switch(unsigned int cpu_mode) > { > add_event_entry(ESCAPE_CODE); >- if (in_kernel) >- add_event_entry(KERNEL_ENTER_SWITCH_CODE); >- else >- add_event_entry(KERNEL_EXIT_SWITCH_CODE); >+ switch (cpu_mode) { >+ case CPU_MODE_USER: >+ add_event_entry(KERNEL_EXIT_SWITCH_CODE); >+ break; >+ case CPU_MODE_KERNEL: >+ add_event_entry(KERNEL_ENTER_SWITCH_CODE); >+ break; >+ case CPU_MODE_XEN: >+ add_event_entry(XEN_ENTER_SWITCH_CODE); >+ break; >+ default: >+ break; >+ } >+} >+ >+static void add_domain_switch(unsigned long domain_id) >+{ >+ add_event_entry(ESCAPE_CODE); >+ add_event_entry(DOMAIN_SWITCH_CODE); >+ add_event_entry(domain_id); > } > > static void >@@ -303,7 +323,7 @@ static void add_sample_entry(unsigned lo > } > > >-static void add_us_sample(struct mm_struct * mm, struct op_sample * s) >+static int add_us_sample(struct mm_struct * mm, struct op_sample * s) > { > unsigned long cookie; > off_t offset; >@@ -312,7 +332,7 @@ static void add_us_sample(struct mm_stru > > if (!cookie) { > atomic_inc(&oprofile_stats.sample_lost_no_mapping); >- return; >+ return 0; > } > > if (cookie != last_cookie) { >@@ -321,6 +341,8 @@ static void add_us_sample(struct mm_stru > } > > add_sample_entry(offset, s->event); >+ >+ return 1; > } > > >@@ -328,15 +350,17 @@ static void add_us_sample(struct mm_stru > * sample is converted into a persistent dentry/offset pair > * for later lookup from userspace. > */ >-static void add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel) >+static int add_sample(struct mm_struct * mm, struct op_sample * s, int cpu_mode) > { >- if (in_kernel) { >+ if (cpu_mode >= CPU_MODE_KERNEL) { > add_sample_entry(s->eip, s->event); >+ return 1; > } else if (mm) { >- add_us_sample(mm, s); >+ return add_us_sample(mm, s); > } else { > atomic_inc(&oprofile_stats.sample_lost_no_mm); > } >+ return 0; > } > > >@@ -358,9 +382,9 @@ static struct mm_struct * take_tasks_mm( > } > > >-static inline int is_ctx_switch(unsigned long val) >+static inline int is_code(unsigned long val) > { >- return val == ~0UL; >+ return val == ESCAPE_CODE; > } > > >@@ -453,6 +477,12 @@ static void mark_done(int cpu) > cpus_clear(marked_cpus); > } > >+typedef enum { >+ sb_bt_ignore = -2, >+ sb_buffer_start, >+ sb_bt_start, >+ sb_sample_start, >+} sync_buffer_state; > > /* Sync one of the CPU's buffers into the global event buffer. > * Here we need to go through each batch of samples punctuated >@@ -466,9 +496,11 @@ void sync_buffer(int cpu) > struct mm_struct *mm = NULL; > struct task_struct * new; > unsigned long cookie = 0; >- int in_kernel = 1; >+ int cpu_mode = 1; > unsigned int i; >+ sync_buffer_state state = sb_buffer_start; > unsigned long available; >+ int domain_switch = 0; > > down(&buffer_sem); > >@@ -481,11 +513,19 @@ void sync_buffer(int cpu) > for (i=0; i < available; ++i) { > struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos]; > >- if (is_ctx_switch(s->eip)) { >- if (s->event <= 1) { >+ if (is_code(s->eip) && !domain_switch) { >+ if (s->event <= CPU_MODE_XEN) { > /* kernel/userspace switch */ >- in_kernel = s->event; >- add_kernel_ctx_switch(s->event); >+ cpu_mode = s->event; >+ if (state == sb_buffer_start) >+ state = sb_sample_start; >+ add_cpu_mode_switch(s->event); >+ } else if (s->event == CPU_TRACE_BEGIN) { >+ state = sb_bt_start; >+ add_event_entry(ESCAPE_CODE); >+ add_event_entry(TRACE_BEGIN_CODE); >+ } else if (s->event == CPU_DOMAIN_SWITCH) { >+ domain_switch = 1; > } else { > struct mm_struct * oldmm = mm; > >@@ -499,7 +539,17 @@ void sync_buffer(int cpu) > add_user_ctx_switch(new, cookie); > } > } else { >- add_sample(mm, s, in_kernel); >+ if (domain_switch) { >+ add_domain_switch(s->eip); >+ domain_switch = 0; >+ } else { >+ if (state >= sb_bt_start && >+ !add_sample(mm, s, cpu_mode)) { >+ if (state == sb_bt_start) { >+ state = sb_bt_ignore; >+ } >+ } >+ } > } > > increment_tail(cpu_buf); >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/cpu_buffer.c /root/linux-2.6.9/drivers/oprofile/cpu_buffer.c >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/cpu_buffer.c 2004-10-18 17:53:06.000000000 -0400 >+++ /root/linux-2.6.9/drivers/oprofile/cpu_buffer.c 2007-07-17 12:56:40.000000000 -0400 >@@ -6,6 +6,10 @@ > * > * @author John Levon <levon@movementarian.org> > * >+ * Modified by Aravind Menon for Xen >+ * These modifications are: >+ * Copyright (C) 2005 Hewlett-Packard Co. >+ * > * Each CPU has a local buffer that stores PC value/event > * pairs. We also log context switches when we notice them. > * Eventually each CPU's buffer is processed into the global >@@ -21,6 +25,7 @@ > #include <linux/vmalloc.h> > #include <linux/errno.h> > >+#include "event_buffer.h" > #include "cpu_buffer.h" > #include "buffer_sync.h" > #include "oprof.h" >@@ -32,6 +37,8 @@ static void wq_sync_buffer(void *); > #define DEFAULT_TIMER_EXPIRE (HZ / 10) > int work_enabled; > >+static int32_t current_domain = COORDINATOR_DOMAIN; >+ > static void __free_cpu_buffers(int num) > { > int i; >@@ -148,8 +155,8 @@ static void increment_head(struct oprofi > * > * is_kernel is needed because on some architectures you cannot > * tell if you are in kernel or user space simply by looking at >- * eip. We tag this in the buffer by generating kernel enter/exit >- * events whenever is_kernel changes >+ * pc. We tag this in the buffer by generating kernel/user (and xen) >+ * enter events whenever cpu_mode changes > */ > void oprofile_add_sample(unsigned long eip, unsigned int is_kernel, > unsigned long event, int cpu) >@@ -157,7 +164,7 @@ void oprofile_add_sample(unsigned long e > struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu]; > struct task_struct * task; > >- is_kernel = !!is_kernel; >+ WARN_ON(is_kernel > CPU_MODE_XEN); > > cpu_buf->sample_received++; > >@@ -178,7 +185,9 @@ void oprofile_add_sample(unsigned long e > } > > /* notice a task switch */ >- if (cpu_buf->last_task != task) { >+ /* if not processing other domain samples */ >+ if (cpu_buf->last_task != task && >+ (current_domain == COORDINATOR_DOMAIN)) { > cpu_buf->last_task = task; > cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL; > cpu_buf->buffer[cpu_buf->head_pos].event = (unsigned long)task; >@@ -202,6 +211,68 @@ void cpu_buffer_reset(struct oprofile_cp > cpu_buf->last_task = NULL; > } > >+/* CRL - this is almost a complete copy of oprofile_add_sample; switch >+ to log_sample like RHEL-5 does */ >+void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) >+{ >+ struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; >+ struct task_struct * task; >+ >+ cpu_buf->sample_received++; >+ >+ if (nr_available_slots(cpu_buf) < 3) { >+ cpu_buf->sample_lost_overflow++; >+ return; >+ } >+ >+ task = current; >+ >+ /* notice a switch from user->kernel or vice versa */ >+ if (cpu_buf->last_is_kernel != is_kernel) { >+ cpu_buf->last_is_kernel = is_kernel; >+ cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL; >+ cpu_buf->buffer[cpu_buf->head_pos].event = is_kernel; >+ increment_head(cpu_buf); >+ } >+ >+ /* notice a task switch */ >+ /* if not processing other domain samples */ >+ if (cpu_buf->last_task != task && >+ (current_domain == COORDINATOR_DOMAIN)) { >+ cpu_buf->last_task = task; >+ cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL; >+ cpu_buf->buffer[cpu_buf->head_pos].event = (unsigned long)task; >+ increment_head(cpu_buf); >+ } >+ >+ cpu_buf->buffer[cpu_buf->head_pos].eip = pc; >+ cpu_buf->buffer[cpu_buf->head_pos].event = event; >+ increment_head(cpu_buf); >+} >+ >+int oprofile_add_domain_switch(int32_t domain_id) >+{ >+ struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; >+ >+ /* should have space for switching into and out of domain >+ (2 slots each) plus one sample and one cpu mode switch */ >+ if (((nr_available_slots(cpu_buf) < 6) && >+ (domain_id != COORDINATOR_DOMAIN)) || >+ (nr_available_slots(cpu_buf) < 2)) >+ return 0; >+ >+ cpu_buf->buffer[cpu_buf->head_pos].eip = ESCAPE_CODE; >+ cpu_buf->buffer[cpu_buf->head_pos].event = CPU_DOMAIN_SWITCH; >+ increment_head(cpu_buf); >+ >+ cpu_buf->buffer[cpu_buf->head_pos].eip = domain_id; >+ cpu_buf->buffer[cpu_buf->head_pos].event = 0; >+ increment_head(cpu_buf); >+ >+ current_domain = domain_id; >+ >+ return 1; >+} > > /* > * This serves to avoid cpu buffer overflow, and makes sure >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/cpu_buffer.h /root/linux-2.6.9/drivers/oprofile/cpu_buffer.h >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/cpu_buffer.h 2004-10-18 17:55:27.000000000 -0400 >+++ /root/linux-2.6.9/drivers/oprofile/cpu_buffer.h 2007-07-17 12:56:40.000000000 -0400 >@@ -48,4 +48,10 @@ extern struct oprofile_cpu_buffer cpu_bu > > void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); > >+#define CPU_MODE_USER 0 >+#define CPU_MODE_KERNEL 1 >+#define CPU_MODE_XEN 2 >+#define CPU_TRACE_BEGIN 3 >+#define CPU_DOMAIN_SWITCH 4 >+ > #endif /* OPROFILE_CPU_BUFFER_H */ >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/event_buffer.h /root/linux-2.6.9/drivers/oprofile/event_buffer.h >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/event_buffer.h 2004-10-18 17:53:21.000000000 -0400 >+++ /root/linux-2.6.9/drivers/oprofile/event_buffer.h 2007-07-17 12:56:40.000000000 -0400 >@@ -32,7 +32,13 @@ void wake_up_buffer_waiter(void); > #define KERNEL_EXIT_SWITCH_CODE 5 > #define MODULE_LOADED_CODE 6 > #define CTX_TGID_CODE 7 >- >+#define TRACE_BEGIN_CODE 8 >+#define XEN_ENTER_SWITCH_CODE 10 >+#define DOMAIN_SWITCH_CODE 11 >+ >+/* Constant used to refer to coordinator domain (Xen) */ >+#define COORDINATOR_DOMAIN -1 >+ > /* add data to the event buffer */ > void add_event_entry(unsigned long data); > >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/oprofile_files.c /root/linux-2.6.9/drivers/oprofile/oprofile_files.c >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/drivers/oprofile/oprofile_files.c 2004-10-18 17:54:08.000000000 -0400 >+++ /root/linux-2.6.9/drivers/oprofile/oprofile_files.c 2007-07-17 13:04:08.000000000 -0400 >@@ -5,10 +5,18 @@ > * @remark Read the file COPYING > * > * @author John Levon <levon@movementarian.org> >+ * >+ * Modified by Aravind Menon for Xen >+ * These modifications are: >+ * Copyright (C) 2005 Hewlett-Packard Co. > */ > > #include <linux/fs.h> > #include <linux/oprofile.h> >+#include <linux/mutex.h> >+#include <linux/ctype.h> >+ >+#include <asm/uaccess.h> > > #include "event_buffer.h" > #include "oprofile_stats.h" >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/include/linux/oprofile.h /root/linux-2.6.9/include/linux/oprofile.h >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/include/linux/oprofile.h 2004-10-18 17:54:37.000000000 -0400 >+++ /root/linux-2.6.9/include/linux/oprofile.h 2007-07-17 13:01:37.000000000 -0400 >@@ -16,7 +16,11 @@ > #include <linux/types.h> > #include <linux/spinlock.h> > #include <asm/atomic.h> >- >+ >+#ifdef CONFIG_XEN >+#include <xen/interface/xenoprof.h> >+#endif >+ > struct super_block; > struct dentry; > struct file_operations; >@@ -59,6 +63,13 @@ void oprofile_arch_exit(void); > extern void oprofile_add_sample(unsigned long eip, unsigned int is_kernel, > unsigned long event, int cpu); > >+/* Use this instead when the PC value is not from the regs. Doesn't >+ * backtrace. */ >+void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event); >+ >+/* add a domain switch entry */ >+int oprofile_add_domain_switch(int32_t domain_id); >+ > /** > * Create a file of the given name as a child of the given root, with > * the specified file operations. >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/include/xen/interface/xen.h /root/linux-2.6.9/include/xen/interface/xen.h >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/include/xen/interface/xen.h 2007-07-17 13:09:56.000000000 -0400 >+++ /root/linux-2.6.9/include/xen/interface/xen.h 2007-07-17 12:56:40.000000000 -0400 >@@ -116,6 +116,7 @@ > #define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */ > #define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ > #define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ >+#define VIRQ_XENOPROF 7 /* V. XenOprofile interrupt: new sample available */ > #define NR_VIRQS 8 > > /* >diff -Nurp /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/include/xen/interface/xenoprof.h /root/linux-2.6.9/include/xen/interface/xenoprof.h >--- /tmp/kernel-RHEL-4/kernel/kernel-2.6.9/linux-2.6.9/include/xen/interface/xenoprof.h 1969-12-31 19:00:00.000000000 -0500 >+++ /root/linux-2.6.9/include/xen/interface/xenoprof.h 2007-07-17 12:56:40.000000000 -0400 >@@ -0,0 +1,110 @@ >+/****************************************************************************** >+ * xenoprof.h >+ * >+ * Interface for enabling system wide profiling based on hardware performance >+ * counters >+ * >+ * Copyright (C) 2005 Hewlett-Packard Co. >+ * Written by Aravind Menon & Jose Renato Santos >+ */ >+ >+#ifndef __XEN_PUBLIC_XENOPROF_H__ >+#define __XEN_PUBLIC_XENOPROF_H__ >+ >+/* >+ * Commands to HYPERVISOR_xenoprof_op(). >+ */ >+#define XENOPROF_init 0 >+#define XENOPROF_reset_active_list 1 >+#define XENOPROF_reset_passive_list 2 >+#define XENOPROF_set_active 3 >+#define XENOPROF_set_passive 4 >+#define XENOPROF_reserve_counters 5 >+#define XENOPROF_counter 6 >+#define XENOPROF_setup_events 7 >+#define XENOPROF_enable_virq 8 >+#define XENOPROF_start 9 >+#define XENOPROF_stop 10 >+#define XENOPROF_disable_virq 11 >+#define XENOPROF_release_counters 12 >+#define XENOPROF_shutdown 13 >+#define XENOPROF_get_buffer 14 >+#define XENOPROF_last_op 14 >+ >+#define MAX_OPROF_EVENTS 32 >+#define MAX_OPROF_DOMAINS 25 >+#define XENOPROF_CPU_TYPE_SIZE 64 >+ >+/* Xenoprof performance events (not Xen events) */ >+struct event_log { >+ uint64_t eip; >+ uint8_t mode; >+ uint8_t event; >+}; >+ >+/* Xenoprof buffer shared between Xen and domain - 1 per VCPU */ >+struct xenoprof_buf { >+ uint32_t event_head; >+ uint32_t event_tail; >+ uint32_t event_size; >+ uint32_t vcpu_id; >+ uint64_t xen_samples; >+ uint64_t kernel_samples; >+ uint64_t user_samples; >+ uint64_t lost_samples; >+ struct event_log event_log[1]; >+}; >+typedef struct xenoprof_buf xenoprof_buf_t; >+DEFINE_XEN_GUEST_HANDLE(xenoprof_buf_t); >+ >+struct xenoprof_init { >+ int32_t num_events; >+ int32_t is_primary; >+ char cpu_type[XENOPROF_CPU_TYPE_SIZE]; >+}; >+typedef struct xenoprof_init xenoprof_init_t; >+DEFINE_XEN_GUEST_HANDLE(xenoprof_init_t); >+ >+struct xenoprof_get_buffer { >+ int32_t max_samples; >+ int32_t nbuf; >+ int32_t bufsize; >+ uint64_t buf_maddr; >+}; >+typedef struct xenoprof_get_buffer xenoprof_get_buffer_t; >+DEFINE_XEN_GUEST_HANDLE(xenoprof_get_buffer_t); >+ >+struct xenoprof_counter { >+ uint32_t ind; >+ uint64_t count; >+ uint32_t enabled; >+ uint32_t event; >+ uint32_t hypervisor; >+ uint32_t kernel; >+ uint32_t user; >+ uint64_t unit_mask; >+}; >+typedef struct xenoprof_counter xenoprof_counter_t; >+DEFINE_XEN_GUEST_HANDLE(xenoprof_counter_t); >+ >+typedef struct xenoprof_passive { >+ uint16_t domain_id; >+ int32_t max_samples; >+ int32_t nbuf; >+ int32_t bufsize; >+ uint64_t buf_maddr; >+} xenoprof_passive_t; >+DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t); >+ >+ >+#endif /* __XEN_PUBLIC_XENOPROF_H__ */ >+ >+/* >+ * Local variables: >+ * mode: C >+ * c-set-style: "BSD" >+ * c-basic-offset: 4 >+ * tab-width: 4 >+ * indent-tabs-mode: nil >+ * End: >+ */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 245582
: 159969