Index: sys/kern/kern_umtx.c =================================================================== --- sys/kern/kern_umtx.c (revision 248077) +++ sys/kern/kern_umtx.c (working copy) @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,11 @@ #define _UMUTEX_TRY 1 #define _UMUTEX_WAIT 2 +#ifdef UMTX_PROFILING +#define UPROF_PERC_BIGGER(w, f, sw, sf) \ + (((w) > (sw)) || ((w) == (sw) && (f) > (sf))) +#endif + /* Priority inheritance mutex info. */ struct umtx_pi { /* Owner thread */ @@ -157,8 +163,8 @@ TAILQ_HEAD(,umtx_pi) uc_pi_list; #ifdef UMTX_PROFILING - int length; - int max_length; + u_int length; + u_int max_length; #endif }; @@ -252,6 +258,117 @@ "max_length1", CTLFLAG_RD, &umtxq_chains[1][i].max_length, 0, NULL); } } + +static int +sysctl_debug_umtx_chains_peaks(SYSCTL_HANDLER_ARGS) +{ + char buf[512]; + struct sbuf sb; + struct umtxq_chain *uc; + u_int fract, i, j, tot, whole; + u_int sf0, sf1, sf2, sf3, sf4; + u_int si0, si1, si2, si3, si4; + u_int sw0, sw1, sw2, sw3, sw4; + + sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); + for (i = 0; i < 2; i++) { + tot = 0; + for (j = 0; j < UMTX_CHAINS; ++j) { + uc = &umtxq_chains[i][j]; + mtx_lock(&uc->uc_lock); + tot += uc->max_length; + mtx_unlock(&uc->uc_lock); + } + if (tot == 0) + sbuf_printf(&sb, "%u) Empty ", i); + else { + sf0 = sf1 = sf2 = sf3 = sf4 = 0; + si0 = si1 = si2 = si3 = si4 = 0; + sw0 = sw1 = sw2 = sw3 = sw4 = 0; + for (j = 0; j < UMTX_CHAINS; j++) { + uc = &umtxq_chains[i][j]; + mtx_lock(&uc->uc_lock); + whole = uc->max_length * 100; + mtx_unlock(&uc->uc_lock); + fract = (whole % tot) * 100; + if (UPROF_PERC_BIGGER(whole, fract, sw0, sf0)) { + sf0 = fract; + si0 = j; + sw0 = whole; + } else if (UPROF_PERC_BIGGER(whole, fract, sw1, + sf1)) { + sf1 = fract; + si1 = j; + sw1 = whole; + } else if (UPROF_PERC_BIGGER(whole, fract, sw2, + sf2)) { + sf2 = fract; + si2 = j; + sw2 = whole; + } else if (UPROF_PERC_BIGGER(whole, fract, sw3, + sf3)) { + sf3 = fract; + si3 = j; + sw3 = whole; + } else if (UPROF_PERC_BIGGER(whole, fract, sw4, + sf4)) { + sf4 = fract; + si4 = j; + sw4 = whole; + } + } + sbuf_printf(&sb, "queue %u:\n", i); + sbuf_printf(&sb, "1st: %u.%u%% idx: %u\n", sw0 / tot, + sf0 / tot, si0); + sbuf_printf(&sb, "2nd: %u.%u%% idx: %u\n", sw1 / tot, + sf1 / tot, si1); + sbuf_printf(&sb, "3rd: %u.%u%% idx: %u\n", sw2 / tot, + sf2 / tot, si2); + sbuf_printf(&sb, "4th: %u.%u%% idx: %u\n", sw3 / tot, + sf3 / tot, si3); + sbuf_printf(&sb, "5th: %u.%u%% idx: %u\n", sw4 / tot, + sf4 / tot, si4); + } + } + sbuf_trim(&sb); + sbuf_finish(&sb); + sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); + sbuf_delete(&sb); + return (0); +} + +static int +sysctl_debug_umtx_chains_clear(SYSCTL_HANDLER_ARGS) +{ + struct umtxq_chain *uc; + u_int i, j; + int clear, error; + + clear = 0; + error = sysctl_handle_int(oidp, &clear, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + if (clear != 0) { + for (i = 0; i < 2; ++i) { + for (j = 0; j < UMTX_CHAINS; ++j) { + uc = &umtxq_chains[i][j]; + mtx_lock(&uc->uc_lock); + uc->length = 0; + uc->max_length = 0; + mtx_unlock(&uc->uc_lock); + } + } + } + return (0); +} + +SYSCTL_PROC(_debug_umtx_chains, OID_AUTO, clear, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0, + sysctl_debug_umtx_chains_clear, "I", "Clear umtx chains statistics"); +SYSCTL_PROC(_debug_umtx_chains, OID_AUTO, peaks, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0, + sysctl_debug_umtx_chains_peaks, "A", "Highest peaks in chains max length"); #endif static void