Index: arch/amd64/amd64/lock_machdep.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/lock_machdep.c,v retrieving revision 1.10 diff -u -p -r1.10 lock_machdep.c --- arch/amd64/amd64/lock_machdep.c 19 Mar 2016 11:34:22 -0000 1.10 +++ arch/amd64/amd64/lock_machdep.c 25 Jan 2017 07:11:32 -0000 @@ -30,6 +30,7 @@ void __mp_lock_init(struct __mp_lock *mpl) { memset(mpl->mpl_cpus, 0, sizeof(mpl->mpl_cpus)); + mpl->mpl_acquired = 0; mpl->mpl_users = 0; mpl->mpl_ticket = 0; } @@ -43,12 +44,18 @@ __mp_lock_init(struct __mp_lock *mpl) extern int __mp_lock_spinout; #endif -static __inline void +static __inline uint64_t __mp_lock_spin(struct __mp_lock *mpl, u_int me) { #ifndef MP_LOCKDEBUG - while (mpl->mpl_ticket != me) + uint64_t spins = 0; + + while (mpl->mpl_ticket != me) { SPINLOCK_SPIN_HOOK; + spins++; + } + + return (spins); #else int nticks = __mp_lock_spinout; @@ -59,6 +66,8 @@ __mp_lock_spin(struct __mp_lock *mpl, u_ db_printf("__mp_lock(%p): lock spun out", mpl); Debugger(); } + + return (0); #endif } @@ -77,14 +86,28 @@ void __mp_lock(struct __mp_lock *mpl) { struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()]; - long rf = read_rflags(); + unsigned int depth; + long rf; + uint64_t tic, toc; + rf = read_rflags(); disable_intr(); - if (cpu->mplc_depth++ == 0) + depth = cpu->mplc_depth++; + if (depth == 0) cpu->mplc_ticket = fetch_and_add(&mpl->mpl_users, 1); write_rflags(rf); - __mp_lock_spin(mpl, cpu->mplc_ticket); + tic = rdtsc(); + cpu->mplc_spins += __mp_lock_spin(mpl, cpu->mplc_ticket); + toc = rdtsc(); + + if (depth == 0) { + cpu->mplc_acquires++; + cpu->mplc_spintime += toc - tic; + mpl->mpl_acquired = toc; + } + + cpu->mplc_uptime = toc; } void @@ -92,6 +115,7 @@ __mp_unlock(struct __mp_lock *mpl) { struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()]; long rf = read_rflags(); + uint64_t now; #ifdef MP_LOCKDEBUG if (!__mp_lock_held(mpl)) { @@ -100,10 +124,16 @@ __mp_unlock(struct __mp_lock *mpl) } #endif + now = rdtsc(); + disable_intr(); - if (--cpu->mplc_depth == 0) + if (--cpu->mplc_depth == 0) { + cpu->mplc_holdtime += now - mpl->mpl_acquired; mpl->mpl_ticket++; + } write_rflags(rf); + + cpu->mplc_uptime = now; } int @@ -111,13 +141,19 @@ __mp_release_all(struct __mp_lock *mpl) { struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()]; long rf = read_rflags(); + uint64_t now; int rv; + now = rdtsc(); + disable_intr(); + cpu->mplc_holdtime += now - mpl->mpl_acquired; rv = cpu->mplc_depth; cpu->mplc_depth = 0; mpl->mpl_ticket++; write_rflags(rf); + + cpu->mplc_uptime = now; return (rv); } Index: arch/amd64/amd64/machdep.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v retrieving revision 1.223 diff -u -p -r1.223 machdep.c --- arch/amd64/amd64/machdep.c 9 Oct 2016 11:25:39 -0000 1.223 +++ arch/amd64/amd64/machdep.c 25 Jan 2017 07:11:32 -0000 @@ -502,6 +502,39 @@ cpu_sysctl(int *name, u_int namelen, voi /* NOTREACHED */ } +int +sysctl_mplock(struct __mp_lock *mpl, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + struct kinfo_mplock *kinfo; + struct __mp_lock_cpu *mplc; + struct kinfo_mplock *kcpu; + size_t len; + unsigned int i; + int rv; + + kinfo = mallocarray(MAXCPUS, sizeof(*kinfo), M_TEMP, M_WAITOK); + len = sizeof(*kinfo) * MAXCPUS; + + for (i = 0; i < MAXCPUS; i++) { + mplc = &mpl->mpl_cpus[i]; + kcpu = &kinfo[i]; + + kcpu->mpl_cpu = i; + kcpu->mpl_uptime = mplc->mplc_uptime; + kcpu->mpl_spintime = mplc->mplc_spintime; + kcpu->mpl_holdtime = mplc->mplc_holdtime; + kcpu->mpl_spins = mplc->mplc_spins; + kcpu->mpl_acquires = mplc->mplc_acquires; + } + + rv = sysctl_rdstruct(oldp, oldlenp, newp, kinfo, len); + + free(kinfo, M_TEMP, len); + + return (rv); +} + /* * Send an interrupt to process. * Index: arch/amd64/include/mplock.h =================================================================== RCS file: /cvs/src/sys/arch/amd64/include/mplock.h,v retrieving revision 1.3 diff -u -p -r1.3 mplock.h --- arch/amd64/include/mplock.h 14 Mar 2014 02:08:57 -0000 1.3 +++ arch/amd64/include/mplock.h 25 Jan 2017 07:11:32 -0000 @@ -28,12 +28,19 @@ #define _MACHINE_MPLOCK_H_ struct __mp_lock_cpu { + uint64_t mplc_uptime; + uint64_t mplc_acquires; + uint64_t mplc_holdtime; + uint64_t mplc_spintime; + uint64_t mplc_spins; + u_int mplc_ticket; u_int mplc_depth; -}; +} __aligned(64); struct __mp_lock { struct __mp_lock_cpu mpl_cpus[MAXCPUS]; + uint64_t mpl_acquired; volatile u_int mpl_ticket; u_int mpl_users; }; @@ -47,6 +54,7 @@ int __mp_release_all(struct __mp_lock *) int __mp_release_all_but_one(struct __mp_lock *); void __mp_acquire_count(struct __mp_lock *, int); int __mp_lock_held(struct __mp_lock *); +int sysctl_mplock(struct __mp_lock *, void *, size_t *, void *, size_t); #endif Index: kern/kern_lock.c =================================================================== RCS file: /cvs/src/sys/kern/kern_lock.c,v retrieving revision 1.47 diff -u -p -r1.47 kern_lock.c --- kern/kern_lock.c 19 Jun 2016 11:54:33 -0000 1.47 +++ kern/kern_lock.c 25 Jan 2017 07:11:32 -0000 @@ -82,4 +82,11 @@ _kernel_lock_held(void) { return (__mp_lock_held(&kernel_lock)); } + +int +sysctl_locks_kernel(void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ + return (sysctl_mplock(&kernel_lock, oldp, oldlenp, newp, newlen)); +} + #endif /* MULTIPROCESSOR */ Index: kern/kern_sysctl.c =================================================================== RCS file: /cvs/src/sys/kern/kern_sysctl.c,v retrieving revision 1.321 diff -u -p -r1.321 kern_sysctl.c --- kern/kern_sysctl.c 21 Jan 2017 05:42:03 -0000 1.321 +++ kern/kern_sysctl.c 25 Jan 2017 07:11:32 -0000 @@ -132,6 +132,7 @@ int sysctl_proc_vmmap(int *, u_int, void int sysctl_intrcnt(int *, u_int, void *, size_t *); int sysctl_sensors(int *, u_int, void *, size_t *, void *, size_t); int sysctl_cptime2(int *, u_int, void *, size_t *, void *, size_t); +int sysctl_locks(int *, u_int, void *, size_t *, void *, size_t); void fill_file(struct kinfo_file *, struct file *, struct filedesc *, int, struct vnode *, struct process *, struct proc *, struct socket *, int); @@ -298,6 +299,7 @@ kern_sysctl(int *name, u_int namelen, vo case KERN_WATCHDOG: case KERN_EVCOUNT: case KERN_TIMECOUNTER: + case KERN_LOCK: case KERN_CPTIME2: case KERN_FILE: break; @@ -390,6 +392,11 @@ kern_sysctl(int *name, u_int namelen, vo p)); case KERN_FILE: return (sysctl_file(name + 1, namelen - 1, oldp, oldlenp, p)); +#ifdef MULTIPROCESSOR + case KERN_LOCK: + return (sysctl_locks(name + 1, namelen - 1, oldp, oldlenp, + newp, newlen)); +#endif #endif case KERN_MBSTAT: { extern struct cpumem *mbstat; @@ -2330,6 +2337,25 @@ sysctl_sensors(int *name, u_int namelen, free(us, M_TEMP, sizeof(*us)); return (ret); } + +#ifdef MULTIPROCESSOR +int +sysctl_locks(int *name, u_int namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + if (namelen != 1) + return (ENOTDIR); + + switch (name[0]) { + case KERN_LOCK_KERNEL: + return (sysctl_locks_kernel(oldp, oldlenp, newp, newlen)); + case KERN_LOCK_SCHED: + return (sysctl_locks_sched(oldp, oldlenp, newp, newlen)); + default: + return (ENOENT); + } +} +#endif #endif /* SMALL_KERNEL */ Index: kern/sched_bsd.c =================================================================== RCS file: /cvs/src/sys/kern/sched_bsd.c,v retrieving revision 1.43 diff -u -p -r1.43 sched_bsd.c --- kern/sched_bsd.c 9 Mar 2016 13:38:50 -0000 1.43 +++ kern/sched_bsd.c 25 Jan 2017 07:11:32 -0000 @@ -711,4 +711,12 @@ sysctl_hwperfpolicy(void *oldp, size_t * } return 0; } + +#ifdef MULTIPROCESSOR +int +sysctl_locks_sched(void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ + return (sysctl_mplock(&sched_lock, oldp, oldlenp, newp, newlen)); +} +#endif #endif Index: sys/sysctl.h =================================================================== RCS file: /cvs/src/sys/sys/sysctl.h,v retrieving revision 1.171 diff -u -p -r1.171 sysctl.h --- sys/sysctl.h 21 Jan 2017 05:42:03 -0000 1.171 +++ sys/sysctl.h 25 Jan 2017 07:11:32 -0000 @@ -184,7 +184,8 @@ struct ctlname { #define KERN_GLOBAL_PTRACE 81 /* allow ptrace globally */ #define KERN_CONSBUFSIZE 82 /* int: console message buffer size */ #define KERN_CONSBUF 83 /* console message buffer */ -#define KERN_MAXID 84 /* number of valid kern ids */ +#define KERN_LOCK 84 +#define KERN_MAXID 85 /* number of valid kern ids */ #define CTL_KERN_NAMES { \ { 0, 0 }, \ @@ -801,6 +802,29 @@ struct kinfo_file { } /* + * KERN_LOCK + */ +#define KERN_LOCK_KERNEL 1 +#define KERN_LOCK_SCHED 2 +#define KERN_LOCK_MAXID 3 + +#define CTL_KERN_LOCK_NAMES { \ + { NULL, 0 }, \ + { "kernel", 0 }, \ + { "sched", 0 }, \ +} + +struct kinfo_mplock { + unsigned int mpl_cpu; + + uint64_t mpl_uptime; /* how long has the cpu been running */ + uint64_t mpl_spintime; /* time spent spinning on the lock */ + uint64_t mpl_holdtime; /* time spent holding the lock */ + uint64_t mpl_spins; /* how many spins to acquire */ + uint64_t mpl_acquires; /* how many times taking the lock */ +}; + +/* * CTL_FS identifiers */ #define FS_POSIX 1 /* POSIX flags */ @@ -951,6 +975,10 @@ int kern_sysctl(int *, u_int, void *, si struct proc *); int hw_sysctl(int *, u_int, void *, size_t *, void *, size_t, struct proc *); +#ifdef MULTIPROCESSOR +int sysctl_locks_kernel(void *, size_t *, void *, size_t); +int sysctl_locks_sched(void *, size_t *, void *, size_t); +#endif #ifdef DEBUG int debug_sysctl(int *, u_int, void *, size_t *, void *, size_t, struct proc *);