diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2009-10-14 09:07:51 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2009-10-14 09:07:51 +0100 |
commit | 0482af4d96d0a48c0e7eb9f9033408c014de9a4d (patch) | |
tree | cd5f29e8439383e5ed3ca6b6a3aa8a10c2ca06b6 /xen | |
parent | c637aa4f78d48ffcd39b8352a7fd325add0f89f9 (diff) | |
download | xen-0482af4d96d0a48c0e7eb9f9033408c014de9a4d.tar.gz xen-0482af4d96d0a48c0e7eb9f9033408c014de9a4d.tar.bz2 xen-0482af4d96d0a48c0e7eb9f9033408c014de9a4d.zip |
Spinlock profiling (enable in build with lock_profile=y)
Adds new tool xenlockprof to run from dom0.
From: Juergen Gross <juergen.gross@ts.fujitsu.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen')
-rw-r--r-- | xen/Rules.mk | 7 | ||||
-rw-r--r-- | xen/arch/x86/domain.c | 2 | ||||
-rw-r--r-- | xen/arch/x86/xen.lds.S | 7 | ||||
-rw-r--r-- | xen/common/domain.c | 7 | ||||
-rw-r--r-- | xen/common/keyhandler.c | 20 | ||||
-rw-r--r-- | xen/common/spinlock.c | 258 | ||||
-rw-r--r-- | xen/common/sysctl.c | 12 | ||||
-rw-r--r-- | xen/include/public/sysctl.h | 35 | ||||
-rw-r--r-- | xen/include/xen/sched.h | 2 | ||||
-rw-r--r-- | xen/include/xen/spinlock.h | 97 |
10 files changed, 438 insertions, 9 deletions
diff --git a/xen/Rules.mk b/xen/Rules.mk index 3f141c33bc..a28efaf902 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -6,6 +6,7 @@ verbose ?= n perfc ?= n perfc_arrays ?= n +lock_profile ?= n crash_debug ?= n frame_pointer ?= n @@ -52,7 +53,9 @@ CFLAGS-$(verbose) += -DVERBOSE 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) @@ -61,10 +64,6 @@ 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__ ALL_OBJS := $(ALL_OBJS-y) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 20d3e3fc80..61a605e19f 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -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 --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 5de98dff64..242f8bcb11 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -62,6 +62,13 @@ SECTIONS *(.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 --git a/xen/common/domain.c b/xen/common/domain.c index 86f0743a34..465aa00a44 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -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 --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index d8122ca096..844d890df7 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -347,6 +347,20 @@ static struct keyhandler perfc_reset_keyhandler = { }; #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 --git a/xen/common/spinlock.c b/xen/common/spinlock.c index a17f0b2124..e6ad0436f5 100644 --- a/xen/common/spinlock.c +++ b/xen/common/spinlock.c @@ -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_is_locked(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 --git a/xen/common/sysctl.c b/xen/common/sysctl.c index 4723de8dc1..dbe6fc1083 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -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_sysctl_t) u_sysctl) 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 --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index f17cd45072..6dccf310e7 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -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; @@ -454,6 +454,38 @@ struct xen_sysctl_page_offline_op { #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; uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ @@ -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 --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index d37c83fccb..3bf3a6aacd 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -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 --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h index a952f0700d..7c1a8fbe80 100644 --- a/xen/include/xen/spinlock.h +++ b/xen/include/xen/spinlock.h @@ -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 { |