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
This commit is contained in:
Attilio Rao 2013-03-09 15:31:19 +00:00
parent 784bcaa1dc
commit 1fc8c346d5

View File

@ -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