kernel - Add additional fields to kinfo_cputime
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 24 Aug 2010 04:50:29 +0000 (21:50 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 24 Aug 2010 04:50:29 +0000 (21:50 -0700)
* Add a message field and address to allow the kernel to report contention
  points on the cpus to userland.

* Enhance the mplock and token subsystems to record contention points.

* Enhance the scheduler to record contention information in the
  per-cpu cpu_time structure.

26 files changed:
sys/emulation/linux/i386/linprocfs/linprocfs_subr.c
sys/emulation/ndis/kern_ndis.c
sys/emulation/ndis/subr_ntoskrnl.c
sys/kern/kern_mplock.c
sys/kern/lwkt_thread.c
sys/kern/lwkt_token.c
sys/kern/subr_disk.c
sys/kern/subr_kobj.c
sys/kern/subr_rman.c
sys/kern/sys_pipe.c
sys/kern/vfs_lock.c
sys/kern/vfs_mount.c
sys/kern/vfs_subr.c
sys/kern/vfs_sync.c
sys/sys/kinfo.h
sys/sys/thread.h
sys/vfs/gnu/ext2fs/ext2_ihash.c
sys/vfs/hpfs/hpfs_hash.c
sys/vfs/hpfs/hpfs_vfsops.c
sys/vfs/isofs/cd9660/cd9660_node.c
sys/vfs/msdosfs/msdosfs_denode.c
sys/vfs/ntfs/ntfs_ihash.c
sys/vfs/udf/udf_vfsops.c
sys/vfs/ufs/ufs_ihash.c
sys/vm/vm_vmspace.c
sys/vm/vm_zeroidle.c

index 8108b59..48a0f22 100644 (file)
@@ -403,7 +403,7 @@ vfs_findname(vfs_namemap_t *nm, char *buf, int buflen)
 void
 linprocfs_init(void)
 {
-       lwkt_token_init(&pfs_token, 1);
+       lwkt_token_init(&pfs_token, 1, "linprocfs");
 } 
 
 void
index 2f9efdd..7778125 100644 (file)
@@ -246,7 +246,7 @@ ndis_create_kthreads(void)
        struct ndis_req         *r;
        int                     i, error = 0;
 
-       lwkt_token_init(&ndis_thr_token, 1);
+       lwkt_token_init(&ndis_thr_token, 1, "ndis");
 
        STAILQ_INIT(&ndis_ttodo);
        STAILQ_INIT(&ndis_itodo);
index 2889a11..8c69c14 100644 (file)
@@ -184,7 +184,7 @@ static MALLOC_DEFINE(M_NDIS, "ndis", "ndis emulation");
 int
 ntoskrnl_libinit(void)
 {
-       lwkt_token_init(&ntoskrnl_dispatchtoken, 1);
+       lwkt_token_init(&ntoskrnl_dispatchtoken, 1, "ndiskrnl");
        ntoskrnl_init_lock(&ntoskrnl_global);
        TAILQ_INIT(&ntoskrnl_reflist);
        return(0);
index 14e2a5a..12c2705 100644 (file)
@@ -109,6 +109,7 @@ _get_mplock_contested(const char *file, int line)
        globaldata_t gd = mycpu;
        int ov;
        int nv;
+       const void **stkframe = (const void **)&file;
 
        ++mplock_contention_count;
        for (;;) {
@@ -120,6 +121,7 @@ _get_mplock_contested(const char *file, int line)
                        if (atomic_cmpset_int(&mp_lock, ov, gd->gd_cpuid))
                                break;
                } else {
+                       gd->gd_curthread->td_mplock_stallpc = stkframe[-1];
                        loggiant(beg);
                        lwkt_switch();
                        loggiant(end);
index 48c498c..e273cbb 100644 (file)
@@ -44,6 +44,7 @@
 #include <sys/kernel.h>
 #include <sys/proc.h>
 #include <sys/rtprio.h>
+#include <sys/kinfo.h>
 #include <sys/queue.h>
 #include <sys/sysctl.h>
 #include <sys/kthread.h>
@@ -501,6 +502,8 @@ lwkt_switch(void)
     int mpheld;
 #endif
     int didaccumulate;
+    const char *lmsg;  /* diagnostic - 'systat -pv 1' */
+    const void *laddr;
 
     /*
      * Switching from within a 'fast' (non thread switched) interrupt or IPI
@@ -654,6 +657,8 @@ lwkt_switch(void)
                    continue;
                }
            }
+           cpu_time.cp_msg[0] = 0;
+           cpu_time.cp_stallpc = 0;
            goto haveidle;
        }
 
@@ -664,7 +669,7 @@ lwkt_switch(void)
 #ifdef SMP
            (ntd->td_mpcount == 0 || mpheld || cpu_try_mplock()) &&
 #endif
-           (!TD_TOKS_HELD(ntd) || lwkt_getalltokens(ntd))
+           (!TD_TOKS_HELD(ntd) || lwkt_getalltokens(ntd, &lmsg, &laddr))
        ) {
 #ifdef SMP
            clr_mplock_contention_mask(gd);
@@ -672,9 +677,16 @@ lwkt_switch(void)
            goto havethread;
        }
 
+       lmsg = NULL;
+       laddr = NULL;
+
 #ifdef SMP
        /* Reload mpheld (it become stale after mplock/token ops) */
        mpheld = MP_LOCK_HELD();
+       if (ntd->td_mpcount && mpheld == 0) {
+           lmsg = "mplock";
+           laddr = ntd->td_mplock_stallpc;
+       }
 #endif
 
        /*
@@ -743,7 +755,10 @@ lwkt_switch(void)
                 * the (almost) top.
                 */
                if (didaccumulate)
-                       break;
+                       break;          /* try again from the top, almost */
+               if (lmsg)
+                   strlcpy(cpu_time.cp_msg, lmsg, sizeof(cpu_time.cp_msg));
+               cpu_time.cp_stallpc = (uintptr_t)laddr;
                goto haveidle;
            }
 
@@ -755,7 +770,7 @@ lwkt_switch(void)
 #ifdef SMP
                (ntd->td_mpcount == 0 || mpheld || cpu_try_mplock()) &&
 #endif
-               (!TD_TOKS_HELD(ntd) || lwkt_getalltokens(ntd))
+               (!TD_TOKS_HELD(ntd) || lwkt_getalltokens(ntd, &lmsg, &laddr))
            ) {
 #ifdef SMP
                    clr_mplock_contention_mask(gd);
@@ -765,6 +780,11 @@ lwkt_switch(void)
 #ifdef SMP
            /* Reload mpheld (it become stale after mplock/token ops) */
            mpheld = MP_LOCK_HELD();
+           if (ntd->td_mpcount && mpheld == 0) {
+               lmsg = "mplock";
+               laddr = ntd->td_mplock_stallpc;
+           }
+
            if (ntd->td_pri >= TDPRI_KERN_LPSCHED && ntd->td_fairq_accum >= 0)
                nquserok = 0;
 #endif
index ccb251f..aed1be2 100644 (file)
@@ -227,7 +227,7 @@ _lwkt_tokref_init(lwkt_tokref_t ref, lwkt_token_t tok, thread_t td)
  * Called from a critical section.
  */
 int
-lwkt_getalltokens(thread_t td)
+lwkt_getalltokens(thread_t td, const char **msgp, const void **addrp)
 {
        lwkt_tokref_t scan;
        lwkt_tokref_t ref;
@@ -268,6 +268,8 @@ lwkt_getalltokens(thread_t td)
                         * Otherwise we failed to acquire all the tokens.
                         * Undo and return.
                         */
+                       *msgp = tok->t_desc;
+                       *addrp = scan->tr_stallpc;
                        atomic_add_long(&tok->t_collisions, 1);
                        lwkt_relalltokens(td);
                        return(FALSE);
@@ -391,7 +393,7 @@ _lwkt_trytokref(lwkt_tokref_t ref, thread_t td)
  */
 static __inline
 void
-_lwkt_gettokref(lwkt_tokref_t ref, thread_t td)
+_lwkt_gettokref(lwkt_tokref_t ref, thread_t td, const void **stkframe)
 {
        if ((ref->tr_flags & LWKT_TOKEN_MPSAFE) == 0)
                get_mplock();
@@ -407,6 +409,7 @@ _lwkt_gettokref(lwkt_tokref_t ref, thread_t td)
                 * return tr_tok->t_ref should be assigned to this specific
                 * ref.
                 */
+               ref->tr_stallpc = stkframe[-1];
                atomic_add_long(&ref->tr_tok->t_collisions, 1);
                logtoken(fail, ref);
                lwkt_switch();
@@ -425,7 +428,7 @@ lwkt_gettoken(lwkt_token_t tok)
        KKASSERT(ref < &td->td_toks_end);
        _lwkt_tokref_init(ref, tok, td);
        ++td->td_toks_stop;
-       _lwkt_gettokref(ref, td);
+       _lwkt_gettokref(ref, td, (const void **)&tok);
 }
 
 lwkt_token_t
@@ -440,7 +443,7 @@ lwkt_getpooltoken(void *ptr)
        tok = _lwkt_token_pool_lookup(ptr);
        _lwkt_tokref_init(ref, tok, td);
        ++td->td_toks_stop;
-       _lwkt_gettokref(ref, td);
+       _lwkt_gettokref(ref, td, (const void **)&ptr);
        return(tok);
 }
 
@@ -510,7 +513,7 @@ lwkt_token_pool_init(void)
        int i;
 
        for (i = 0; i < LWKT_NUM_POOL_TOKENS; ++i)
-               lwkt_token_init(&pool_tokens[i], 1);
+               lwkt_token_init(&pool_tokens[i], 1, "pool");
 }
 
 lwkt_token_t
@@ -524,7 +527,7 @@ lwkt_token_pool_lookup(void *ptr)
  * acquiring the token and released after releasing the token.
  */
 void
-lwkt_token_init(lwkt_token_t tok, int mpsafe)
+lwkt_token_init(lwkt_token_t tok, int mpsafe, const char *desc)
 {
        tok->t_ref = NULL;
        tok->t_flags = mpsafe ? LWKT_TOKEN_MPSAFE : 0;
index 0bd0636..4840046 100644 (file)
@@ -1258,7 +1258,7 @@ disk_init(void)
                                         objcache_malloc_free,
                                         &disk_msg_malloc_args);
 
-       lwkt_token_init(&disklist_token, 1);
+       lwkt_token_init(&disklist_token, 1, "disks");
 
        /*
         * Initialize the reply-only port which acts as a message drain
index 749ac5f..5433fdf 100644 (file)
@@ -66,7 +66,7 @@ static int kobj_next_id = 1;
 static void
 kobj_init_token(void *arg)
 {
-       lwkt_token_init(&kobj_token, 1);
+       lwkt_token_init(&kobj_token, 1, "kobj");
 }
 
 SYSINIT(kobj, SI_BOOT1_LOCK, SI_ORDER_ANY, kobj_init_token, NULL);
index e98e89e..4e6588a 100644 (file)
@@ -91,7 +91,7 @@ rman_init(struct rman *rm)
        if (once == 0) {
                once = 1;
                TAILQ_INIT(&rman_head);
-               lwkt_token_init(&rman_tok, 1);
+               lwkt_token_init(&rman_tok, 1, "rman");
        }
 
        if (rm->rm_type == RMAN_UNINIT)
@@ -103,7 +103,7 @@ rman_init(struct rman *rm)
        rm->rm_slock = kmalloc(sizeof *rm->rm_slock, M_RMAN, M_NOWAIT);
        if (rm->rm_slock == NULL)
                return ENOMEM;
-       lwkt_token_init(rm->rm_slock, 1);
+       lwkt_token_init(rm->rm_slock, 1, "rmanslock");
 
        lwkt_gettoken(&rman_tok);
        TAILQ_INSERT_TAIL(&rman_head, rm, rm_link);
index 2fbc592..95c0475 100644 (file)
@@ -381,8 +381,8 @@ pipe_create(struct pipe **cpipep)
        vfs_timestamp(&cpipe->pipe_ctime);
        cpipe->pipe_atime = cpipe->pipe_ctime;
        cpipe->pipe_mtime = cpipe->pipe_ctime;
-       lwkt_token_init(&cpipe->pipe_rlock, 1);
-       lwkt_token_init(&cpipe->pipe_wlock, 1);
+       lwkt_token_init(&cpipe->pipe_rlock, 1, "piper");
+       lwkt_token_init(&cpipe->pipe_wlock, 1, "pipew");
        return (0);
 }
 
index 7e70cd9..6982ef5 100644 (file)
@@ -415,7 +415,7 @@ vnode_ctor(void *obj, void *private, int ocflags)
 {
        struct vnode *vp = obj;
 
-       lwkt_token_init(&vp->v_token, 1);
+       lwkt_token_init(&vp->v_token, 1, "vnode");
        lockinit(&vp->v_lock, "vnode", 0, 0);
        ccms_dataspace_init(&vp->v_ccms);
        TAILQ_INIT(&vp->v_namecache);
index 40c30cd..7595a63 100644 (file)
@@ -135,9 +135,9 @@ static TAILQ_HEAD(,bio_ops) bio_ops_list = TAILQ_HEAD_INITIALIZER(bio_ops_list);
 void
 vfs_mount_init(void)
 {
-       lwkt_token_init(&mountlist_token, 1);
-       lwkt_token_init(&mntvnode_token, 1);
-       lwkt_token_init(&mntid_token, 1);
+       lwkt_token_init(&mountlist_token, 1, "mntlist");
+       lwkt_token_init(&mntvnode_token, 1, "mntvnode");
+       lwkt_token_init(&mntid_token, 1, "mntid");
        TAILQ_INIT(&mountscan_list);
        TAILQ_INIT(&mntvnodescan_list);
        mount_init(&dummymount);
@@ -320,7 +320,7 @@ void
 mount_init(struct mount *mp)
 {
        lockinit(&mp->mnt_lock, "vfslock", 0, 0);
-       lwkt_token_init(&mp->mnt_token, 1);
+       lwkt_token_init(&mp->mnt_token, 1, "permnt");
 
        TAILQ_INIT(&mp->mnt_nvnodelist);
        TAILQ_INIT(&mp->mnt_reservedvnlist);
index 6d0efe3..635355b 100644 (file)
@@ -195,7 +195,7 @@ vfs_subr_init(void)
                     KvaSize / factor2);
        desiredvnodes = imax(desiredvnodes, maxproc * 8);
 
-       lwkt_token_init(&spechash_token, 1);
+       lwkt_token_init(&spechash_token, 1, "spechash");
 }
 
 /*
index 66f3657..1f02e39 100644 (file)
@@ -120,7 +120,7 @@ vfs_sync_init(void)
        syncer_workitem_pending = hashinit(syncer_maxdelay, M_DEVBUF,
                                            &syncer_mask);
        syncer_maxdelay = syncer_mask + 1;
-       lwkt_token_init(&syncer_token, 1);
+       lwkt_token_init(&syncer_token, 1, "syncer");
 }
 
 /*
index e7123fe..c547c6d 100644 (file)
@@ -74,6 +74,11 @@ struct kinfo_cputime {
        uint64_t        cp_sys;
        uint64_t        cp_intr;
        uint64_t        cp_idle;
+       uint64_t        cp_unused01;
+       uint64_t        cp_unused02;
+       uint64_t        cp_unused03;
+       uint64_t        cp_stallpc;     /* code stall address */
+       char            cp_msg[32];     /* code stall token or mplock */
 };
 
 /*
index 7846409..c31ccca 100644 (file)
@@ -104,6 +104,7 @@ typedef struct lwkt_token {
     struct lwkt_tokref *t_ref;         /* Owning ref or NULL */
     intptr_t           t_flags;        /* MP lock required */
     long               t_collisions;   /* Collision counter */
+    const char         *t_desc;        /* Descriptive name */
 } lwkt_token;
 
 #define LWKT_TOKEN_MPSAFE      0x0001
@@ -134,6 +135,7 @@ struct lwkt_tokref {
     lwkt_token_t       tr_tok;         /* token in question */
     struct thread      *tr_owner;      /* me */
     intptr_t           tr_flags;       /* copy of t_flags */
+    const void         *tr_stallpc;    /* stalled at pc */
 };
 
 #define MAXCPUFIFO      16     /* power of 2 */
@@ -229,7 +231,6 @@ struct thread {
     __uint64_t td_sticks;      /* Statclock hits in system mode (uS) */
     __uint64_t td_iticks;      /* Statclock hits processing intr (uS) */
     int                td_locks;       /* lockmgr lock debugging */
-    int                td_fairq_lticks;        /* fairq wakeup accumulator reset */
     void       *td_dsched_priv1;       /* priv data for I/O schedulers */
     int                td_refs;        /* hold position in gd_tdallq / hold free */
     int                td_nest_count;  /* prevent splz nesting */
@@ -248,6 +249,9 @@ struct thread {
     struct caps_kinfo *td_caps;        /* list of client and server registrations */
     lwkt_tokref_t td_toks_stop;
     struct lwkt_tokref td_toks_array[LWKT_MAXTOKENS];
+    int                td_fairq_lticks;        /* fairq wakeup accumulator reset */
+    int                td_fairq_accum;         /* fairq priority accumulator */
+    const void *td_mplock_stallpc;     /* last mplock stall address */
 #ifdef DEBUG_CRIT_SECTIONS
 #define CRIT_DEBUG_ARRAY_SIZE   32
 #define CRIT_DEBUG_ARRAY_MASK   (CRIT_DEBUG_ARRAY_SIZE - 1)
@@ -255,7 +259,6 @@ struct thread {
     int                td_crit_debug_index;
     int                td_in_crit_report;      
 #endif
-    int                td_fairq_accum;         /* fairq priority accumulator */
     struct md_thread td_mach;
 };
 
@@ -397,10 +400,10 @@ extern void lwkt_passive_release(thread_t);
 extern void lwkt_gettoken(lwkt_token_t);
 extern int  lwkt_trytoken(lwkt_token_t);
 extern void lwkt_reltoken(lwkt_token_t);
-extern int  lwkt_getalltokens(thread_t);
+extern int  lwkt_getalltokens(thread_t, const char **, const void **);
 extern void lwkt_relalltokens(thread_t);
 extern void lwkt_drain_token_requests(void);
-extern void lwkt_token_init(lwkt_token_t, int);
+extern void lwkt_token_init(lwkt_token_t, int, const char *);
 extern void lwkt_token_uninit(lwkt_token_t);
 
 extern void lwkt_token_pool_init(void);
index 686aba7..2121f32 100644 (file)
@@ -69,7 +69,7 @@ ext2_ihashinit(void)
                ext2_ihash <<= 1;
        ext2_ihashtbl = kmalloc(sizeof(void *) * ext2_ihash, M_EXT2IHASH, M_WAITOK|M_ZERO);
        --ext2_ihash;
-       lwkt_token_init(&ext2_ihash_token, 1);
+       lwkt_token_init(&ext2_ihash_token, 1, "ext2ihash");
 }
 
 int
index d329e26..428e1ff 100644 (file)
@@ -69,7 +69,7 @@ hpfs_hphashinit(void)
        lockinit (&hpfs_hphash_lock, "hpfs_hphashlock", 0, 0);
        hpfs_hphashtbl = HASHINIT(desiredvnodes, M_HPFSHASH, M_WAITOK,
            &hpfs_hphash);
-       lwkt_token_init(&hpfs_hphash_token, 1);
+       lwkt_token_init(&hpfs_hphash_token, 1, "hpfsihash");
 }
 
 /*
index 5f3df47..10b37cc 100644 (file)
@@ -500,7 +500,7 @@ hpfs_vget(struct mount *mp, struct vnode *dvp, ino_t ino, struct vnode **vpp)
        if (ino == (ino_t)hpmp->hpm_su.su_rootfno) 
                vsetflags(vp, VROOT);
 
-       lwkt_token_init(&hp->h_interlock, 1);
+       lwkt_token_init(&hp->h_interlock, 1, "hpfsilock");
 
        hp->h_flag = H_INVAL;
        hp->h_vp = vp;
index cf3f5d0..66f397d 100644 (file)
@@ -87,7 +87,7 @@ cd9660_init(struct vfsconf *vfsp)
        isohashtbl = kmalloc(sizeof(void *) * isohash,
                            M_ISOFSMNT, M_WAITOK|M_ZERO);
        --isohash;
-       lwkt_token_init(&cd9660_ihash_token, 1);
+       lwkt_token_init(&cd9660_ihash_token, 1, "cd9660ihash");
        return (0);
 }
 
index b2a2799..5b82fa1 100644 (file)
@@ -122,7 +122,7 @@ msdosfs_init(struct vfsconf *vfsp)
        dehashtbl = kmalloc(sizeof(void *) * dehash, M_MSDOSFSMNT,
                           M_WAITOK|M_ZERO);
        --dehash;
-       lwkt_token_init(&dehash_token, 1);
+       lwkt_token_init(&dehash_token, 1, "msdosihash");
        return (0);
 }
 
index 7af561e..2ce78db 100644 (file)
@@ -70,7 +70,7 @@ ntfs_nthashinit(void)
        lockinit(&ntfs_hashlock, "ntfs_nthashlock", 0, 0);
        ntfs_nthashtbl = HASHINIT(desiredvnodes, M_NTFSNTHASH, M_WAITOK,
            &ntfs_nthash);
-       lwkt_token_init(&ntfs_nthash_slock, 1);
+       lwkt_token_init(&ntfs_nthash_slock, 1, "ntfsihash");
 }
 
 /*
index 84b3a46..2a2909a 100644 (file)
@@ -384,7 +384,7 @@ udf_mountfs(struct vnode *devvp, struct mount *mp)
        brelse(bp);
        bp = NULL;
 
-       lwkt_token_init(&udfmp->hash_token, 1);
+       lwkt_token_init(&udfmp->hash_token, 1, "udfihash");
        udfmp->hashtbl = phashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, &udfmp->hashsz);
 
        return(0);
index ae543f6..6ed2d76 100644 (file)
@@ -68,7 +68,7 @@ ufs_ihashinit(void)
                ihash <<= 1;
        ihashtbl = kmalloc(sizeof(void *) * ihash, M_UFSIHASH, M_WAITOK|M_ZERO);
        --ihash;
-       lwkt_token_init(&ufs_ihash_token, 1);
+       lwkt_token_init(&ufs_ihash_token, 1, "ufsihash");
 }
 
 int
index 80bcee4..eaa3e66 100644 (file)
@@ -97,7 +97,7 @@ sys_vmspace_create(struct vmspace_create_args *uap)
                lwkt_gettoken(&proc_token);
                if (p->p_vkernel == NULL) {
                        vkp->refs = 1;
-                       lwkt_token_init(&vkp->token, 1);
+                       lwkt_token_init(&vkp->token, 1, "vkernel");
                        RB_INIT(&vkp->root);
                        p->p_vkernel = vkp;
                } else {
index 700b773..ae5ff93 100644 (file)
@@ -208,7 +208,6 @@ vm_pagezero(void __unused *arg)
                         * resched has been requested.
                         */
                        while (i < PAGE_SIZE) {
-                               lwkt_yield();
                                if (idlezero_nocache == 1)
                                        bzeront(&pg[i], IDLEZERO_RUN);
                                else