summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_umtx.c
diff options
context:
space:
mode:
authorattilio <attilio@FreeBSD.org>2013-03-09 15:31:19 +0000
committerattilio <attilio@FreeBSD.org>2013-03-09 15:31:19 +0000
commite5b2c298d6ea5a21d324e1fece6e4a8a79ce8532 (patch)
tree715d5262fc753f3ec26f9566b800968c41df02cd /sys/kern/kern_umtx.c
parent5cd5608a27139c5f0b34e02d98738808b3f38ab5 (diff)
downloadFreeBSD-src-e5b2c298d6ea5a21d324e1fece6e4a8a79ce8532.zip
FreeBSD-src-e5b2c298d6ea5a21d324e1fece6e4a8a79ce8532.tar.gz
Improve UMTX_PROFILING:
- Use u_int values for length and max_length values - Add a way to reset the max_length heuristic in order to have the possibility to reuse the mechanism consecutively without rebooting the machine - Add a way to quick display top5 contented buckets in the system for the max_length value. This should give a quick overview on the quality of the hash table distribution. Sponsored by: EMC / Isilon storage division Reviewed by: jeff, davide
Diffstat (limited to 'sys/kern/kern_umtx.c')
-rw-r--r--sys/kern/kern_umtx.c121
1 files changed, 119 insertions, 2 deletions
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
index 2b7e92f..f50a6f9 100644
--- a/sys/kern/kern_umtx.c
+++ b/sys/kern/kern_umtx.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/sbuf.h>
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
@@ -64,6 +65,11 @@ __FBSDID("$FreeBSD$");
#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 @@ struct umtxq_chain {
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 @@ umtx_init_profiling(void)
"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
OpenPOWER on IntegriCloud