WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Spinlock profiling (enable in build with

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Spinlock profiling (enable in build with lock_profile=y)
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 14 Oct 2009 01:15:19 -0700
Delivery-date: Wed, 14 Oct 2009 01:16:14 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1255507671 -3600
# Node ID 10c0942ed2409b740f516b41781e6051e206c984
# Parent  71c859535c6bb7ba543ae3d483c830ca88cf4022
Spinlock profiling (enable in build with lock_profile=y)

Adds new tool xenlockprof to run from dom0.

From: Juergen Gross <juergen.gross@xxxxxxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 tools/libxc/xc_misc.c       |   24 ++++
 tools/libxc/xenctrl.h       |    8 +
 tools/misc/Makefile         |    6 -
 tools/misc/xenlockprof.c    |  136 +++++++++++++++++++++++
 xen/Rules.mk                |    7 -
 xen/arch/x86/domain.c       |    2 
 xen/arch/x86/xen.lds.S      |    7 +
 xen/common/domain.c         |    7 -
 xen/common/keyhandler.c     |   20 +++
 xen/common/spinlock.c       |  258 ++++++++++++++++++++++++++++++++++++++++++++
 xen/common/sysctl.c         |   12 ++
 xen/include/public/sysctl.h |   35 +++++
 xen/include/xen/sched.h     |    2 
 xen/include/xen/spinlock.h  |   97 ++++++++++++++++
 14 files changed, 609 insertions(+), 12 deletions(-)

diff -r 71c859535c6b -r 10c0942ed240 tools/libxc/xc_misc.c
--- a/tools/libxc/xc_misc.c     Wed Oct 14 08:58:47 2009 +0100
+++ b/tools/libxc/xc_misc.c     Wed Oct 14 09:07:51 2009 +0100
@@ -117,6 +117,30 @@ int xc_perfc_control(int xc_handle,
         *nbr_desc = sysctl.u.perfc_op.nr_counters;
     if ( nbr_val )
         *nbr_val = sysctl.u.perfc_op.nr_vals;
+
+    return rc;
+}
+
+int xc_lockprof_control(int xc_handle,
+                        uint32_t opcode,
+                        uint32_t *n_elems,
+                        uint64_t *time,
+                        xc_lockprof_data_t *data)
+{
+    int rc;
+    DECLARE_SYSCTL;
+
+    sysctl.cmd = XEN_SYSCTL_lockprof_op;
+    sysctl.u.lockprof_op.cmd = opcode;
+    sysctl.u.lockprof_op.max_elem = n_elems ? *n_elems : 0;
+    set_xen_guest_handle(sysctl.u.lockprof_op.data, data);
+
+    rc = do_sysctl(xc_handle, &sysctl);
+
+    if (n_elems)
+        *n_elems = sysctl.u.lockprof_op.nr_elem;
+    if (time)
+        *time = sysctl.u.lockprof_op.time;
 
     return rc;
 }
diff -r 71c859535c6b -r 10c0942ed240 tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Wed Oct 14 08:58:47 2009 +0100
+++ b/tools/libxc/xenctrl.h     Wed Oct 14 09:07:51 2009 +0100
@@ -700,6 +700,14 @@ int xc_perfc_control(int xc_handle,
                      int *nbr_desc,
                      int *nbr_val);
 
+typedef xen_sysctl_lockprof_data_t xc_lockprof_data_t;
+/* IMPORTANT: The caller is responsible for mlock()'ing the @data array. */
+int xc_lockprof_control(int xc_handle,
+                        uint32_t opcode,
+                        uint32_t *n_elems,
+                        uint64_t *time,
+                        xc_lockprof_data_t *data);
+
 /**
  * Memory maps a range within one domain to a local address range.  Mappings
  * should be unmapped with munmap and should follow the same rules as mmap
diff -r 71c859535c6b -r 10c0942ed240 tools/misc/Makefile
--- a/tools/misc/Makefile       Wed Oct 14 08:58:47 2009 +0100
+++ b/tools/misc/Makefile       Wed Oct 14 09:07:51 2009 +0100
@@ -10,7 +10,7 @@ CFLAGS   += $(INCLUDES)
 
 HDRS     = $(wildcard *.h)
 
-TARGETS-y := xenperf xenpm xen-tmem-list-parse gtraceview gtracestat
+TARGETS-y := xenperf xenpm xen-tmem-list-parse gtraceview gtracestat 
xenlockprof
 TARGETS-$(CONFIG_X86) += xen-detect xen-hvmctx
 TARGETS := $(TARGETS-y)
 
@@ -22,7 +22,7 @@ INSTALL_BIN-$(CONFIG_X86) += xen-detect
 INSTALL_BIN-$(CONFIG_X86) += xen-detect
 INSTALL_BIN := $(INSTALL_BIN-y)
 
-INSTALL_SBIN-y := xm xen-bugtool xen-python-path xend xenperf xsview xenpm 
xen-tmem-list-parse gtraceview gtracestat
+INSTALL_SBIN-y := xm xen-bugtool xen-python-path xend xenperf xsview xenpm 
xen-tmem-list-parse gtraceview gtracestat xenlockprof
 INSTALL_SBIN-$(CONFIG_X86) += xen-hvmctx
 INSTALL_SBIN := $(INSTALL_SBIN-y)
 
@@ -49,7 +49,7 @@ clean:
 %.o: %.c $(HDRS) Makefile
        $(CC) -c $(CFLAGS) -o $@ $<
 
-xen-hvmctx xenperf xenpm gtracestat: %: %.o Makefile
+xen-hvmctx xenperf xenpm gtracestat xenlockprof: %: %.o Makefile
        $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDFLAGS_libxenctrl)
 
 gtraceview: %: %.o Makefile
diff -r 71c859535c6b -r 10c0942ed240 tools/misc/xenlockprof.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/misc/xenlockprof.c  Wed Oct 14 09:07:51 2009 +0100
@@ -0,0 +1,136 @@
+/* -*-  Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2009 - Juergen Gross - Fujitsu Technology Solutions
+ ****************************************************************************
+ *
+ *        File: xenlockprof.c
+ *      Author: Juergen Gross (juergen.gross@xxxxxxxxxxxxxx)
+ *        Date: Oct 2009
+ * 
+ * Description: 
+ */
+
+#include <xenctrl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+
+static int lock_pages(void *addr, size_t len)
+{
+    int e = 0;
+#ifndef __sun__
+    e = mlock(addr, len);
+#endif
+    return (e);
+}
+
+static void unlock_pages(void *addr, size_t len)
+{
+#ifndef __sun__
+    munlock(addr, len);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+    int                xc_handle;
+    uint32_t           i, j, n;
+    uint64_t           time;
+    double             l, b, sl, sb;
+    char               name[60];
+    xc_lockprof_data_t *data;
+
+    if ((argc > 2) || ((argc == 2) && (strcmp(argv[1], "-r") != 0)))
+    {
+        printf("%s: [-r]\n", argv[0]);
+        printf("no args: print lock profile data\n");
+        printf("    -r : reset profile data\n");
+        return 1;
+    }
+
+    if ((xc_handle = xc_interface_open()) == -1)
+    {
+        fprintf(stderr, "Error opening xc interface: %d (%s)\n",
+                errno, strerror(errno));
+        return 1;
+    }
+
+    if (argc > 1)
+    {
+        if (xc_lockprof_control(xc_handle, XEN_SYSCTL_LOCKPROF_reset, NULL,
+                                NULL, NULL) != 0)
+        {
+            fprintf(stderr, "Error reseting profile data: %d (%s)\n",
+                    errno, strerror(errno));
+            return 1;
+        }
+        return 1;
+    }
+
+    n = 0;
+    if (xc_lockprof_control(xc_handle, XEN_SYSCTL_LOCKPROF_query, &n,
+                            NULL, NULL) != 0)
+    {
+        fprintf(stderr, "Error getting number of profile records: %d (%s)\n",
+                errno, strerror(errno));
+        return 1;
+    }
+
+    n += 32;    /* just to be sure */
+    data = malloc(sizeof(*data) * n);
+    if ((data == NULL) || (lock_pages(data, sizeof(*data) * n) != 0))
+    {
+        fprintf(stderr, "Could not alloc or lock buffers: %d (%s)\n",
+                errno, strerror(errno));
+        return 1;
+    }
+
+    i = n;
+    if ( xc_lockprof_control(xc_handle, XEN_SYSCTL_LOCKPROF_query, &i,
+                             &time, data) != 0)
+    {
+        fprintf(stderr, "Error getting profile records: %d (%s)\n",
+                errno, strerror(errno));
+        return 1;
+    }
+
+    unlock_pages(data, sizeof(*data) * n);
+
+    if (i > n)
+    {
+        printf("data incomplete, %d records are missing!\n\n", i - n);
+        i = n;
+    }
+    sl = 0;
+    sb = 0;
+    for (j = 0; j < i; j++)
+    {
+        switch (data[j].type)
+        {
+        case LOCKPROF_TYPE_GLOBAL:
+            sprintf(name, "global lock %s", data[j].name);
+            break;
+        case LOCKPROF_TYPE_PERDOM:
+            sprintf(name, "domain %d lock %s", data[j].idx, data[j].name);
+            break;
+        default:
+            sprintf(name, "unknown type(%d) %d lock %s", data[j].type,
+                data[j].idx, data[j].name);
+            break;
+        }
+        l = (double)(data[j].lock_time) / 1E+09;
+        b = (double)(data[j].block_time) / 1E+09;
+        sl += l;
+        sb += b;
+        printf("%-50s: lock:%12ld(%20.9fs), block:%12ld(%20.9fs)\n",
+            name, data[j].lock_cnt, l, data[j].block_cnt, b);
+    }
+    l = (double)time / 1E+09;
+    printf("total profiling time: %20.9fs\n", l);
+    printf("total locked time:    %20.9fs\n", sl);
+    printf("total blocked time:   %20.9fs\n", sb);
+
+    return 0;
+}
diff -r 71c859535c6b -r 10c0942ed240 xen/Rules.mk
--- a/xen/Rules.mk      Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/Rules.mk      Wed Oct 14 09:07:51 2009 +0100
@@ -6,6 +6,7 @@ verbose       ?= n
 verbose       ?= n
 perfc         ?= n
 perfc_arrays  ?= n
+lock_profile  ?= n
 crash_debug   ?= n
 frame_pointer ?= n
 
@@ -52,17 +53,15 @@ CFLAGS-$(crash_debug)   += -DCRASH_DEBUG
 CFLAGS-$(crash_debug)   += -DCRASH_DEBUG
 CFLAGS-$(perfc)         += -DPERF_COUNTERS
 CFLAGS-$(perfc_arrays)  += -DPERF_ARRAYS
+CFLAGS-$(lock_profile)  += -DLOCK_PROFILE
 CFLAGS-$(frame_pointer) += -fno-omit-frame-pointer -DCONFIG_FRAME_POINTER
+CFLAGS-$(privileged_stubdoms) += -DPRIVILEGED_STUBDOMS
 
 ifneq ($(max_phys_cpus),)
 CFLAGS-y                += -DMAX_PHYS_CPUS=$(max_phys_cpus)
 endif
 ifneq ($(max_phys_irqs),)
 CFLAGS-y                += -DMAX_PHYS_IRQS=$(max_phys_irqs)
-endif
-
-ifeq ($(privileged_stubdoms),y)
-CFLAGS += -DPRIVILEGED_STUBDOMS
 endif
 
 AFLAGS-y                += -D__ASSEMBLY__
diff -r 71c859535c6b -r 10c0942ed240 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/arch/x86/domain.c     Wed Oct 14 09:07:51 2009 +0100
@@ -32,6 +32,7 @@
 #include <xen/acpi.h>
 #include <xen/pci.h>
 #include <xen/paging.h>
+#include <public/sysctl.h>
 #include <asm/regs.h>
 #include <asm/mc146818rtc.h>
 #include <asm/system.h>
@@ -185,6 +186,7 @@ struct domain *alloc_domain_struct(void)
 
 void free_domain_struct(struct domain *d)
 {
+    lock_profile_deregister_struct(LOCKPROF_TYPE_PERDOM, d);
     free_xenheap_pages(d, get_order_from_bytes(sizeof(*d)));
 }
 
diff -r 71c859535c6b -r 10c0942ed240 xen/arch/x86/xen.lds.S
--- a/xen/arch/x86/xen.lds.S    Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/arch/x86/xen.lds.S    Wed Oct 14 09:07:51 2009 +0100
@@ -61,6 +61,13 @@ SECTIONS
   .data.read_mostly : {
        *(.data.read_mostly)
   } :text
+
+#ifdef LOCK_PROFILE
+  . = ALIGN(32);
+  __lock_profile_start = .;
+  .lockprofile.data : { *(.lockprofile.data) } :text
+  __lock_profile_end = .;
+#endif
 
   . = ALIGN(4096);             /* Init code and data */
   __init_begin = .;
diff -r 71c859535c6b -r 10c0942ed240 xen/common/domain.c
--- a/xen/common/domain.c       Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/common/domain.c       Wed Oct 14 09:07:51 2009 +0100
@@ -29,6 +29,7 @@
 #include <acpi/cpufreq/cpufreq.h>
 #include <asm/debugger.h>
 #include <public/sched.h>
+#include <public/sysctl.h>
 #include <public/vcpu.h>
 #include <xsm/xsm.h>
 #include <xen/trace.h>
@@ -221,13 +222,15 @@ struct domain *domain_create(
     memset(d, 0, sizeof(*d));
     d->domain_id = domid;
 
+    lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain");
+
     if ( xsm_alloc_security_domain(d) != 0 )
         goto fail;
     init_status |= INIT_xsm;
 
     atomic_set(&d->refcnt, 1);
-    spin_lock_init(&d->domain_lock);
-    spin_lock_init(&d->page_alloc_lock);
+    spin_lock_init_prof(d, domain_lock);
+    spin_lock_init_prof(d, page_alloc_lock);
     spin_lock_init(&d->shutdown_lock);
     spin_lock_init(&d->hypercall_deadlock_mutex);
     INIT_PAGE_LIST_HEAD(&d->page_list);
diff -r 71c859535c6b -r 10c0942ed240 xen/common/keyhandler.c
--- a/xen/common/keyhandler.c   Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/common/keyhandler.c   Wed Oct 14 09:07:51 2009 +0100
@@ -347,6 +347,20 @@ static struct keyhandler perfc_reset_key
 };
 #endif
 
+#ifdef LOCK_PROFILE
+extern void spinlock_profile_printall(unsigned char key);
+static struct keyhandler spinlock_printall_keyhandler = {
+    .diagnostic = 1,
+    .u.fn = spinlock_profile_printall,
+    .desc = "print lock profile info"
+};
+extern void spinlock_profile_reset(unsigned char key);
+static struct keyhandler spinlock_reset_keyhandler = {
+    .u.fn = spinlock_profile_reset,
+    .desc = "reset lock profile info"
+};
+#endif
+
 static void run_all_nonirq_keyhandlers(unsigned long unused)
 {
     /* Fire all the non-IRQ-context diagnostic keyhandlers */
@@ -428,6 +442,12 @@ void __init initialize_keytable(void)
     register_keyhandler('p', &perfc_printall_keyhandler);
     register_keyhandler('P', &perfc_reset_keyhandler);
 #endif
+
+#ifdef LOCK_PROFILE
+    register_keyhandler('l', &spinlock_printall_keyhandler);
+    register_keyhandler('L', &spinlock_reset_keyhandler);
+#endif
+
 }
 
 /*
diff -r 71c859535c6b -r 10c0942ed240 xen/common/spinlock.c
--- a/xen/common/spinlock.c     Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/common/spinlock.c     Wed Oct 14 09:07:51 2009 +0100
@@ -1,7 +1,11 @@
+#include <xen/lib.h>
 #include <xen/config.h>
 #include <xen/irq.h>
 #include <xen/smp.h>
+#include <xen/time.h>
 #include <xen/spinlock.h>
+#include <xen/guest_access.h>
+#include <public/sysctl.h>
 #include <asm/processor.h>
 
 #ifndef NDEBUG
@@ -41,56 +45,97 @@ void spin_debug_disable(void)
 
 #endif
 
+#ifdef LOCK_PROFILE
+
+#define LOCK_PROFILE_REL                                               \
+    lock->profile.time_hold += NOW() - lock->profile.time_locked;      \
+    lock->profile.lock_cnt++;
+#define LOCK_PROFILE_VAR    s_time_t block = 0
+#define LOCK_PROFILE_BLOCK  block = block ? : NOW();
+#define LOCK_PROFILE_GOT                                               \
+    lock->profile.time_locked = NOW();                                 \
+    if (block)                                                         \
+    {                                                                  \
+        lock->profile.time_block += lock->profile.time_locked - block; \
+        lock->profile.block_cnt++;                                     \
+    }
+
+#else
+
+#define LOCK_PROFILE_REL
+#define LOCK_PROFILE_VAR
+#define LOCK_PROFILE_BLOCK
+#define LOCK_PROFILE_GOT
+
+#endif
+
 void _spin_lock(spinlock_t *lock)
 {
+    LOCK_PROFILE_VAR;
+
     check_lock(&lock->debug);
     while ( unlikely(!_raw_spin_trylock(&lock->raw)) )
+    {
+        LOCK_PROFILE_BLOCK;
         while ( likely(_raw_spin_is_locked(&lock->raw)) )
             cpu_relax();
+    }
+    LOCK_PROFILE_GOT;
 }
 
 void _spin_lock_irq(spinlock_t *lock)
 {
+    LOCK_PROFILE_VAR;
+
     ASSERT(local_irq_is_enabled());
     local_irq_disable();
     check_lock(&lock->debug);
     while ( unlikely(!_raw_spin_trylock(&lock->raw)) )
     {
+        LOCK_PROFILE_BLOCK;
         local_irq_enable();
         while ( likely(_raw_spin_is_locked(&lock->raw)) )
             cpu_relax();
         local_irq_disable();
     }
+    LOCK_PROFILE_GOT;
 }
 
 unsigned long _spin_lock_irqsave(spinlock_t *lock)
 {
     unsigned long flags;
+    LOCK_PROFILE_VAR;
+
     local_irq_save(flags);
     check_lock(&lock->debug);
     while ( unlikely(!_raw_spin_trylock(&lock->raw)) )
     {
+        LOCK_PROFILE_BLOCK;
         local_irq_restore(flags);
         while ( likely(_raw_spin_is_locked(&lock->raw)) )
             cpu_relax();
         local_irq_save(flags);
     }
+    LOCK_PROFILE_GOT;
     return flags;
 }
 
 void _spin_unlock(spinlock_t *lock)
 {
+    LOCK_PROFILE_REL;
     _raw_spin_unlock(&lock->raw);
 }
 
 void _spin_unlock_irq(spinlock_t *lock)
 {
+    LOCK_PROFILE_REL;
     _raw_spin_unlock(&lock->raw);
     local_irq_enable();
 }
 
 void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
 {
+    LOCK_PROFILE_REL;
     _raw_spin_unlock(&lock->raw);
     local_irq_restore(flags);
 }
@@ -104,13 +149,32 @@ int _spin_trylock(spinlock_t *lock)
 int _spin_trylock(spinlock_t *lock)
 {
     check_lock(&lock->debug);
+#ifndef LOCK_PROFILE
     return _raw_spin_trylock(&lock->raw);
+#else
+    if (!_raw_spin_trylock(&lock->raw)) return 0;
+    lock->profile.time_locked = NOW();
+    return 1;
+#endif
 }
 
 void _spin_barrier(spinlock_t *lock)
 {
+#ifdef LOCK_PROFILE
+    s_time_t block = NOW();
+    u64      loop = 0;
+
+    check_lock(&lock->debug);
+    do { mb(); loop++;} while ( _raw_spin_is_locked(&lock->raw) );
+    if (loop > 1)
+    {
+        lock->profile.time_block += NOW() - block;
+        lock->profile.block_cnt++;
+    }
+#else
     check_lock(&lock->debug);
     do { mb(); } while ( _raw_spin_is_locked(&lock->raw) );
+#endif
     mb();
 }
 
@@ -248,3 +312,197 @@ int _rw_is_write_locked(rwlock_t *lock)
     check_lock(&lock->debug);
     return _raw_rw_is_write_locked(&lock->raw);
 }
+
+#ifdef LOCK_PROFILE
+struct lock_profile_anc {
+    struct lock_profile_qhead *head_q;   /* first head of this type */
+    char                      *name;     /* descriptive string for print */
+};
+
+typedef void lock_profile_subfunc(struct lock_profile *, int32_t, int32_t,
+                                  void *);
+
+extern struct lock_profile *__lock_profile_start;
+extern struct lock_profile *__lock_profile_end;
+
+static s_time_t lock_profile_start = 0;
+static struct lock_profile_anc lock_profile_ancs[LOCKPROF_TYPE_N];
+static struct lock_profile_qhead lock_profile_glb_q;
+static spinlock_t lock_profile_lock = SPIN_LOCK_UNLOCKED;
+
+static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
+{
+    int  i;
+    struct lock_profile_qhead *hq;
+    struct lock_profile *eq;
+
+    spin_lock(&lock_profile_lock);
+    for (i = 0; i < LOCKPROF_TYPE_N; i++)
+    {
+        for (hq = lock_profile_ancs[i].head_q; hq; hq = hq->head_q)
+        {
+            for (eq = hq->elem_q; eq; eq = eq->next)
+            {
+                sub(eq, i, hq->idx, par);
+            }
+        }
+    }
+    spin_unlock(&lock_profile_lock);
+    return;
+}
+
+static void spinlock_profile_print_elem(struct lock_profile *data,
+    int32_t type, int32_t idx, void *par)
+{
+    if (type == LOCKPROF_TYPE_GLOBAL)
+        printk("%s %s:\n", lock_profile_ancs[idx].name, data->name);
+    else
+        printk("%s %d %s:\n", lock_profile_ancs[idx].name, idx, data->name);
+    printk("  lock:%12ld(%08X:%08X), block:%12ld(%08X:%08X)\n",
+        data->lock_cnt, (u32)(data->time_hold >> 32), (u32)data->time_hold,
+        data->block_cnt, (u32)(data->time_block >> 32), (u32)data->time_block);
+    return;
+}
+
+void spinlock_profile_printall(unsigned char key)
+{
+    s_time_t now = NOW();
+    s_time_t diff;
+
+    diff = now - lock_profile_start;
+    printk("Xen lock profile info SHOW  (now = %08X:%08X, "
+        "total = %08X:%08X)\n", (u32)(now>>32), (u32)now,
+        (u32)(diff>>32), (u32)diff);
+    spinlock_profile_iterate(spinlock_profile_print_elem, NULL);
+    return;
+}
+
+static void spinlock_profile_reset_elem(struct lock_profile *data,
+    int32_t type, int32_t idx, void *par)
+{
+    data->lock_cnt = 0;
+    data->block_cnt = 0;
+    data->time_hold = 0;
+    data->time_block = 0;
+    return;
+}
+
+void spinlock_profile_reset(unsigned char key)
+{
+    s_time_t now = NOW();
+
+    if ( key != '\0' )
+        printk("Xen lock profile info RESET (now = %08X:%08X)\n",
+            (u32)(now>>32), (u32)now);
+    lock_profile_start = now;
+    spinlock_profile_iterate(spinlock_profile_reset_elem, NULL);
+    return;
+}
+
+typedef struct {
+    xen_sysctl_lockprof_op_t *pc;
+    int                      rc;
+} spinlock_profile_ucopy_t;
+
+static void spinlock_profile_ucopy_elem(struct lock_profile *data,
+    int32_t type, int32_t idx, void *par)
+{
+    spinlock_profile_ucopy_t *p;
+    xen_sysctl_lockprof_data_t elem;
+
+    p = (spinlock_profile_ucopy_t *)par;
+    if (p->rc)
+        return;
+
+    if (p->pc->nr_elem < p->pc->max_elem)
+    {
+        safe_strcpy(elem.name, data->name);
+        elem.type = type;
+        elem.idx = idx;
+        elem.lock_cnt = data->lock_cnt;
+        elem.block_cnt = data->block_cnt;
+        elem.lock_time = data->time_hold;
+        elem.block_time = data->time_block;
+        if (copy_to_guest_offset(p->pc->data, p->pc->nr_elem, &elem, 1))
+        {
+            p->rc = -EFAULT;
+            return;
+        }
+    }
+    p->pc->nr_elem++;
+    
+    return;
+}
+
+/* Dom0 control of lock profiling */
+int spinlock_profile_control(xen_sysctl_lockprof_op_t *pc)
+{
+    int rc;
+    spinlock_profile_ucopy_t par;
+
+    rc = 0;
+    switch (pc->cmd)
+    {
+    case XEN_SYSCTL_LOCKPROF_reset:
+        spinlock_profile_reset('\0');
+        break;
+    case XEN_SYSCTL_LOCKPROF_query:
+       pc->nr_elem = 0;
+       par.rc = 0;
+       par.pc = pc;
+        spinlock_profile_iterate(spinlock_profile_ucopy_elem, &par);
+        pc->time = NOW() - lock_profile_start;
+       rc = par.rc;
+        break;
+    default:
+        rc = -EINVAL;
+        break;
+    }
+    return rc;
+}
+
+void _lock_profile_register_struct(int32_t type,
+    struct lock_profile_qhead *qhead, int32_t idx, char *name)
+{
+    qhead->idx = idx;
+    spin_lock(&lock_profile_lock);
+    qhead->head_q = lock_profile_ancs[type].head_q;
+    lock_profile_ancs[type].head_q = qhead;
+    lock_profile_ancs[type].name = name;
+    spin_unlock(&lock_profile_lock);
+    return;
+}
+
+void _lock_profile_deregister_struct(int32_t type,
+    struct lock_profile_qhead *qhead)
+{
+    struct lock_profile_qhead **q;
+
+    spin_lock(&lock_profile_lock);
+    for (q = &lock_profile_ancs[type].head_q; *q; q = &((*q)->head_q))
+    {
+        if (*q == qhead)
+        {
+            *q = qhead->head_q;
+            break;
+        }
+    }
+    spin_unlock(&lock_profile_lock);
+    return;
+}
+
+static int __init lock_prof_init(void)
+{
+    struct lock_profile **q;
+
+    for (q = &__lock_profile_start; q < &__lock_profile_end; q++)
+    {
+        (*q)->next = lock_profile_glb_q.elem_q;
+       lock_profile_glb_q.elem_q = *q;
+    }
+    _lock_profile_register_struct(LOCKPROF_TYPE_GLOBAL, &lock_profile_glb_q,
+        0, "Global lock");
+    return 0;
+}
+__initcall(lock_prof_init);
+#endif
diff -r 71c859535c6b -r 10c0942ed240 xen/common/sysctl.c
--- a/xen/common/sysctl.c       Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/common/sysctl.c       Wed Oct 14 09:07:51 2009 +0100
@@ -29,6 +29,9 @@
 
 extern long arch_do_sysctl(
     struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl);
+#ifdef LOCK_PROFILE
+extern int spinlock_profile_control(xen_sysctl_lockprof_op_t *pc);
+#endif
 
 long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
 {
@@ -144,6 +147,15 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysc
     break;
 #endif
 
+#ifdef LOCK_PROFILE
+    case XEN_SYSCTL_lockprof_op:
+    {
+        ret = spinlock_profile_control(&op->u.lockprof_op);
+        if ( copy_to_guest(u_sysctl, op, 1) )
+            ret = -EFAULT;
+    }
+    break;
+#endif
     case XEN_SYSCTL_debug_keys:
     {
         char c;
diff -r 71c859535c6b -r 10c0942ed240 xen/include/public/sysctl.h
--- a/xen/include/public/sysctl.h       Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/include/public/sysctl.h       Wed Oct 14 09:07:51 2009 +0100
@@ -396,7 +396,7 @@ struct xen_sysctl_pm_op {
         struct xen_get_cpufreq_para get_para;
         struct xen_set_cpufreq_gov  set_gov;
         struct xen_set_cpufreq_para set_para;
-        uint64_t get_avgfreq;
+        uint64_aligned_t get_avgfreq;
         struct xen_get_cputopo      get_topo;
         uint32_t                    set_sched_opt_smt;
         uint32_t                    get_max_cstate;
@@ -453,6 +453,38 @@ struct xen_sysctl_page_offline_op {
 #define PG_ONLINE_BROKEN     PG_OFFLINE_BROKEN
 
 #define PG_OFFLINE_OWNER_SHIFT 16
+
+#define XEN_SYSCTL_lockprof_op       11
+/* Sub-operations: */
+#define XEN_SYSCTL_LOCKPROF_reset 1   /* Reset all profile data to zero. */
+#define XEN_SYSCTL_LOCKPROF_query 2   /* Get lock profile information. */
+/* Record-type: */
+#define LOCKPROF_TYPE_GLOBAL      0   /* global lock, idx meaningless */
+#define LOCKPROF_TYPE_PERDOM      1   /* per-domain lock, idx is domid */
+#define LOCKPROF_TYPE_N           2   /* number of types */
+struct xen_sysctl_lockprof_data {
+    char     name[40];     /* lock name (may include up to 2 %d specifiers) */
+    int32_t  type;         /* LOCKPROF_TYPE_??? */
+    int32_t  idx;          /* index (e.g. domain id) */
+    uint64_aligned_t lock_cnt;     /* # of locking succeeded */
+    uint64_aligned_t block_cnt;    /* # of wait for lock */
+    uint64_aligned_t lock_time;    /* nsecs lock held */
+    uint64_aligned_t block_time;   /* nsecs waited for lock */
+};
+typedef struct xen_sysctl_lockprof_data xen_sysctl_lockprof_data_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_lockprof_data_t);
+struct xen_sysctl_lockprof_op {
+    /* IN variables. */
+    uint32_t       cmd;               /* XEN_SYSCTL_LOCKPROF_??? */
+    uint32_t       max_elem;          /* size of output buffer */
+    /* OUT variables (query only). */
+    uint32_t       nr_elem;           /* number of elements available */
+    uint64_aligned_t time;            /* nsecs of profile measurement */
+    /* profile information (or NULL) */
+    XEN_GUEST_HANDLE_64(xen_sysctl_lockprof_data_t) data;
+};
+typedef struct xen_sysctl_lockprof_op xen_sysctl_lockprof_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_lockprof_op_t);
 
 struct xen_sysctl {
     uint32_t cmd;
@@ -471,6 +503,7 @@ struct xen_sysctl {
         struct xen_sysctl_cpu_hotplug       cpu_hotplug;
         struct xen_sysctl_pm_op             pm_op;
         struct xen_sysctl_page_offline_op   page_offline;
+        struct xen_sysctl_lockprof_op       lockprof_op;
         uint8_t                             pad[128];
     } u;
 };
diff -r 71c859535c6b -r 10c0942ed240 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/include/xen/sched.h   Wed Oct 14 09:07:51 2009 +0100
@@ -276,6 +276,8 @@ struct domain
 
     /* transcendent memory, auto-allocated on first tmem op by each domain */
     void *tmem;
+
+    struct lock_profile_qhead profile_head;
 };
 
 struct domain_setup_info
diff -r 71c859535c6b -r 10c0942ed240 xen/include/xen/spinlock.h
--- a/xen/include/xen/spinlock.h        Wed Oct 14 08:58:47 2009 +0100
+++ b/xen/include/xen/spinlock.h        Wed Oct 14 09:07:51 2009 +0100
@@ -19,16 +19,109 @@ struct lock_debug { };
 #define spin_debug_disable() ((void)0)
 #endif
 
+#ifdef LOCK_PROFILE
+/*
+    lock profiling on:
+
+    Global locks which should be subject to profiling must be declared via
+    DEFINE_SPINLOCK.
+
+    For locks in structures further measures are necessary:
+    - the structure definition must include a profile_head with exactly this
+      name:
+
+      struct lock_profile_qhead   profile_head;
+
+    - the single locks which are subject to profiling have to be initialized
+      via
+
+      spin_lock_init_prof(ptr, lock);
+
+      with ptr being the main structure pointer and lock the spinlock field
+
+    - each structure has to be added to profiling with
+
+      lock_profile_register_struct(type, ptr, idx, print);
+
+      with:
+        type:  something like LOCKPROF_TYPE_PERDOM
+        ptr:   pointer to the structure
+        idx:   index of that structure, e.g. domid
+        print: descriptive string like "domain"
+
+    - removing of a structure is done via
+
+      lock_profile_deregister_struct(type, ptr);
+*/
+
+struct lock_profile {
+    struct lock_profile *next;       /* forward link */
+    char                *name;       /* lock name */
+    u64                 lock_cnt;    /* # of complete locking ops */
+    u64                 block_cnt;   /* # of complete wait for lock */
+    s64                 time_hold;   /* cumulated lock time */
+    s64                 time_block;  /* cumulated wait time */
+    s64                 time_locked; /* system time of last locking */
+};
+
+struct lock_profile_qhead {
+    struct lock_profile_qhead *head_q; /* next head of this type */
+    struct lock_profile       *elem_q; /* first element in q */
+    int32_t                   idx;     /* index for printout */
+};
+
+#define _LOCK_PROFILE(name) { 0, name, 0, 0, 0, 0, 0 }
+#define _LOCK_NO_PROFILE _LOCK_PROFILE(NULL)
+#define _LOCK_PROFILE_PTR(name)                                               \
+    static struct lock_profile *__lock_profile_##name __attribute_used__      \
+    __attribute__ ((__section__(".lockprofile.data"))) = &name.profile
+#define _SPIN_LOCK_UNLOCKED(x) { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0,          \
+                                 _LOCK_DEBUG, x }
+#define SPIN_LOCK_UNLOCKED _SPIN_LOCK_UNLOCKED(_LOCK_NO_PROFILE)
+#define DEFINE_SPINLOCK(l)                                                    \
+    spinlock_t l = _SPIN_LOCK_UNLOCKED(_LOCK_PROFILE(#l));                    \
+    _LOCK_PROFILE_PTR(l)
+
+#define spin_lock_init_prof(s, l)                                             \
+    do {                                                                      \
+        (s)->l = (spinlock_t)_SPIN_LOCK_UNLOCKED(_LOCK_PROFILE(#l));          \
+       (s)->l.profile.next = (s)->profile_head.elem_q;                       \
+       (s)->profile_head.elem_q = &((s)->l.profile);                         \
+    } while(0)
+
+void _lock_profile_register_struct(int32_t, struct lock_profile_qhead *,      \
+                                   int32_t, char *);
+void _lock_profile_deregister_struct(int32_t, struct lock_profile_qhead *);
+
+#define lock_profile_register_struct(type, ptr, idx, print)                   \
+    _lock_profile_register_struct(type, &((ptr)->profile_head), idx, print)
+#define lock_profile_deregister_struct(type, ptr)                             \
+    _lock_profile_deregister_struct(type, &((ptr)->profile_head))
+
+#else
+
+struct lock_profile { };
+struct lock_profile_qhead { };
+
+#define SPIN_LOCK_UNLOCKED                                                    \
+    { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0, _LOCK_DEBUG, { } }
+#define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
+
+#define spin_lock_init_prof(s, l) spin_lock_init(&((s)->l))
+#define lock_profile_register_struct(type, ptr, idx, print)
+#define lock_profile_deregister_struct(type, ptr)
+
+#endif
+
 typedef struct {
     raw_spinlock_t raw;
     u16 recurse_cpu:12;
     u16 recurse_cnt:4;
     struct lock_debug debug;
+    struct lock_profile profile;
 } spinlock_t;
 
 
-#define SPIN_LOCK_UNLOCKED { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0, _LOCK_DEBUG }
-#define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
 #define spin_lock_init(l) (*(l) = (spinlock_t)SPIN_LOCK_UNLOCKED)
 
 typedef struct {

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Spinlock profiling (enable in build with lock_profile=y), Xen patchbot-unstable <=