[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [Patch] support of lock profiling in Xen


  • To: Keir Fraser <keir.fraser@xxxxxxxxxxxxx>
  • From: Juergen Gross <juergen.gross@xxxxxxxxxxxxxx>
  • Date: Tue, 13 Oct 2009 15:56:30 +0200
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxx>
  • Delivery-date: Tue, 13 Oct 2009 06:57:07 -0700
  • Domainkey-signature: s=s1536a; d=ts.fujitsu.com; c=nofws; q=dns; h=X-SBRSScore:X-IronPort-AV:Received:X-IronPort-AV: Received:Received:Message-ID:Date:From:Organization: User-Agent:MIME-Version:To:CC:Subject:References: In-Reply-To:X-Enigmail-Version:Content-Type; b=FxogC9GRqPH58PZWGGDoQl7fTk6cV3pCvFrNR2FASED0/jl/nnFxLDLH 85z0QTVC26A/+bjVTDUfbFSj0NmC8qL/DwqcEnOEy0Sf+tYaWQFakRdFb hQUe8ZSiDB++eRVacPastVHfZPtdyXe8IyUL2qDciqPaCdFedwvlgdHau iOraE2K76ofRYt0p4TfmcpwJHs2uP7zU0pkJFiHMfWJ1zwZQpOROMCNTf IwHqmPop+hdieRlxMU/2+NTEvwF6y;
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>

Keir Fraser wrote:
> On 09/10/2009 09:27, "Juergen Gross" <juergen.gross@xxxxxxxxxxxxxx> wrote:
> 
>>> Okay, well this all sounds an acceptable kind of direction. Worth spinning
>>> another patch.
>> Here it is.
>> I managed to avoid the perfc-like stuff completely.
>>
>> Included are 2 global locks defined for profiling and 2 locks in the domain
>> structure.
>>
>> I've added some comments in spinlock.h how to use the profiling in 
>> structures.
>>
>> Tested by compilation and boot of Dom0 with and without profiling enabled.
> 
> Not keen on exposing the lock_profile_funcs[] stuff; that and a few other
> aspects are ratehr clumsy looking. I would rather dynamically
> register/unregister lock-profile blocks; something like:
>    /* domain creation */
>    lock_profile_register_struct(
>        LOCKPROF_TYPE_PERDOMAIN, d, d->domid);
>    /* domain destruction */
>    lock_profile_unregister_struct(d);
> Requires a 'struct lock_profile lock_profile' or similar to be declared
> within the domain structure. No need to hide that definition within a macro
> I expect, nor to specify in advance the 'max # locks'.

Round 3 then :-)

I think a rw-lock is not needed, as reading is a very rare event which will
be executed in parallel less then once a year. ;-)

Better?


Juergen

-- 
Juergen Gross                 Principal Developer Operating Systems
TSP ES&S SWE OS6                       Telephone: +49 (0) 89 636 47950
Fujitsu Technolgy Solutions               e-mail: juergen.gross@xxxxxxxxxxxxxx
Otto-Hahn-Ring 6                        Internet: ts.fujitsu.com
D-81739 Muenchen                 Company details: ts.fujitsu.com/imprint.html
diff -r 1d7221667204 tools/libxc/xc_misc.c
--- a/tools/libxc/xc_misc.c     Thu Oct 08 09:24:32 2009 +0100
+++ b/tools/libxc/xc_misc.c     Tue Oct 13 15:52:27 2009 +0200
@@ -121,6 +121,30 @@
     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;
+}
+
 int xc_getcpuinfo(int xc_handle, int max_cpus,
                   xc_cpuinfo_t *info, int *nr_cpus)
 {
diff -r 1d7221667204 tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Thu Oct 08 09:24:32 2009 +0100
+++ b/tools/libxc/xenctrl.h     Tue Oct 13 15:52:27 2009 +0200
@@ -700,6 +700,14 @@
                      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 1d7221667204 tools/misc/Makefile
--- a/tools/misc/Makefile       Thu Oct 08 09:24:32 2009 +0100
+++ b/tools/misc/Makefile       Tue Oct 13 15:52:27 2009 +0200
@@ -10,7 +10,7 @@
 
 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 := $(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 @@
 %.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 1d7221667204 tools/misc/xenlockprof.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/misc/xenlockprof.c  Tue Oct 13 15:52:27 2009 +0200
@@ -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 1d7221667204 xen/Rules.mk
--- a/xen/Rules.mk      Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/Rules.mk      Tue Oct 13 15:52:27 2009 +0200
@@ -6,6 +6,7 @@
 verbose       ?= n
 perfc         ?= n
 perfc_arrays  ?= n
+lock_profile  ?= n
 crash_debug   ?= n
 frame_pointer ?= n
 
@@ -49,6 +50,7 @@
 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
 
 ifneq ($(max_phys_cpus),)
diff -r 1d7221667204 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/arch/x86/domain.c     Tue Oct 13 15:52:27 2009 +0200
@@ -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 @@
 
 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 1d7221667204 xen/arch/x86/xen.lds.S
--- a/xen/arch/x86/xen.lds.S    Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/arch/x86/xen.lds.S    Tue Oct 13 15:52:27 2009 +0200
@@ -62,6 +62,13 @@
        *(.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 = .;
   .init.text : {
diff -r 1d7221667204 xen/common/domain.c
--- a/xen/common/domain.c       Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/common/domain.c       Tue Oct 13 15:52:27 2009 +0200
@@ -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 @@
     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 1d7221667204 xen/common/keyhandler.c
--- a/xen/common/keyhandler.c   Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/common/keyhandler.c   Tue Oct 13 15:52:27 2009 +0200
@@ -347,6 +347,20 @@
 };
 #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 @@
     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 1d7221667204 xen/common/spinlock.c
--- a/xen/common/spinlock.c     Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/common/spinlock.c     Tue Oct 13 15:52:27 2009 +0200
@@ -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 @@
 
 #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)
 {
     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 @@
     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 1d7221667204 xen/common/sysctl.c
--- a/xen/common/sysctl.c       Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/common/sysctl.c       Tue Oct 13 15:52:27 2009 +0200
@@ -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 @@
     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 1d7221667204 xen/include/public/sysctl.h
--- a/xen/include/public/sysctl.h       Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/include/public/sysctl.h       Tue Oct 13 15:52:27 2009 +0200
@@ -454,6 +454,38 @@
 
 #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_t lock_cnt;     /* # of locking succeeded */
+    uint64_t block_cnt;    /* # of wait for lock */
+    uint64_t lock_time;    /* nsecs lock held */
+    uint64_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_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;
     uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
@@ -471,6 +503,7 @@
         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 1d7221667204 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/include/xen/sched.h   Tue Oct 13 15:52:27 2009 +0200
@@ -276,6 +276,8 @@
 
     /* 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 1d7221667204 xen/include/xen/spinlock.h
--- a/xen/include/xen/spinlock.h        Thu Oct 08 09:24:32 2009 +0100
+++ b/xen/include/xen/spinlock.h        Tue Oct 13 15:52:27 2009 +0200
@@ -19,16 +19,109 @@
 #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-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.