aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2013-10-02 11:43:52 -0700
committerBrian Behlendorf <[email protected]>2013-10-25 13:57:25 -0700
commit2d37239a28b8b2ddc0e8312093f8d8810c6351fa (patch)
tree93885704a95285d91b28baca4df8fe57ea3efcf5 /module
parent0b1401ee911c5a0c0bdb7a8e6ad36840cea3af24 (diff)
Add visibility in to dmu_tx_assign times
This change adds a new kstat to gain some visibility into the amount of time spent in each call to dmu_tx_assign. A histogram is exported via the new dmu_tx_assign file. The information contained in this histogram is the frequency dmu_tx_assign took to complete given an interval range. Signed-off-by: Prakash Surya <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module')
-rw-r--r--module/zfs/dmu_tx.c5
-rw-r--r--module/zfs/spa_stats.c106
2 files changed, 111 insertions, 0 deletions
diff --git a/module/zfs/dmu_tx.c b/module/zfs/dmu_tx.c
index 17982a04e..7b6223956 100644
--- a/module/zfs/dmu_tx.c
+++ b/module/zfs/dmu_tx.c
@@ -1077,12 +1077,15 @@ dmu_tx_unassign(dmu_tx_t *tx)
int
dmu_tx_assign(dmu_tx_t *tx, txg_how_t txg_how)
{
+ hrtime_t before;
int err;
ASSERT(tx->tx_txg == 0);
ASSERT(txg_how == TXG_WAIT || txg_how == TXG_NOWAIT);
ASSERT(!dsl_pool_sync_context(tx->tx_pool));
+ before = gethrtime();
+
/* If we might wait, we must not hold the config lock. */
ASSERT(txg_how != TXG_WAIT || !dsl_pool_config_held(tx->tx_pool));
@@ -1097,6 +1100,8 @@ dmu_tx_assign(dmu_tx_t *tx, txg_how_t txg_how)
txg_rele_to_quiesce(&tx->tx_txgh);
+ spa_tx_assign_add_nsecs(tx->tx_pool->dp_spa, gethrtime() - before);
+
return (0);
}
diff --git a/module/zfs/spa_stats.c b/module/zfs/spa_stats.c
index 16ccbb0ad..789e8c3e6 100644
--- a/module/zfs/spa_stats.c
+++ b/module/zfs/spa_stats.c
@@ -504,16 +504,122 @@ spa_txg_history_set_io(spa_t *spa, uint64_t txg, uint64_t nread,
return (error);
}
+/*
+ * ==========================================================================
+ * SPA TX Assign Histogram Routines
+ * ==========================================================================
+ */
+
+/*
+ * Tx statistics - Information exported regarding dmu_tx_assign time.
+ */
+
+/*
+ * When the kstat is written zero all buckets. When the kstat is read
+ * count the number of trailing buckets set to zero and update ks_ndata
+ * such that they are not output.
+ */
+static int
+spa_tx_assign_update(kstat_t *ksp, int rw)
+{
+ spa_t *spa = ksp->ks_private;
+ spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
+ int i;
+
+ if (rw == KSTAT_WRITE) {
+ for (i = 0; i < ssh->count; i++)
+ ((kstat_named_t *)ssh->private)[i].value.ui64 = 0;
+ }
+
+ for (i = ssh->count; i > 0; i--)
+ if (((kstat_named_t *)ssh->private)[i-1].value.ui64 != 0)
+ break;
+
+ ksp->ks_ndata = i;
+ ksp->ks_data_size = i * sizeof(kstat_named_t);
+
+ return (0);
+}
+
+static void
+spa_tx_assign_init(spa_t *spa)
+{
+ spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
+ char name[KSTAT_STRLEN];
+ kstat_named_t *ks;
+ kstat_t *ksp;
+ int i;
+
+ mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
+
+ ssh->count = 42; /* power of two buckets for 1ns to 2,199s */
+ ssh->size = ssh->count * sizeof(kstat_named_t);
+ ssh->private = kmem_alloc(ssh->size, KM_SLEEP);
+
+ (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
+ name[KSTAT_STRLEN-1] = '\0';
+
+ for (i = 0; i < ssh->count; i++) {
+ ks = &((kstat_named_t *)ssh->private)[i];
+ ks->data_type = KSTAT_DATA_UINT64;
+ ks->value.ui64 = 0;
+ (void) snprintf(ks->name, KSTAT_STRLEN, "%llu ns",
+ (u_longlong_t)1 << i);
+ }
+
+ ksp = kstat_create(name, 0, "dmu_tx_assign", "misc",
+ KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
+ ssh->kstat = ksp;
+
+ if (ksp) {
+ ksp->ks_lock = &ssh->lock;
+ ksp->ks_data = ssh->private;
+ ksp->ks_ndata = ssh->count;
+ ksp->ks_data_size = ssh->size;
+ ksp->ks_private = spa;
+ ksp->ks_update = spa_tx_assign_update;
+ kstat_install(ksp);
+ }
+}
+
+static void
+spa_tx_assign_destroy(spa_t *spa)
+{
+ spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
+ kstat_t *ksp;
+
+ ksp = ssh->kstat;
+ if (ksp)
+ kstat_delete(ksp);
+
+ kmem_free(ssh->private, ssh->size);
+ mutex_destroy(&ssh->lock);
+}
+
+void
+spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs)
+{
+ spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
+ uint64_t idx = 0;
+
+ while (((1 << idx) < nsecs) && (idx < ssh->size - 1))
+ idx++;
+
+ atomic_inc_64(&((kstat_named_t *)ssh->private)[idx].value.ui64);
+}
+
void
spa_stats_init(spa_t *spa)
{
spa_read_history_init(spa);
spa_txg_history_init(spa);
+ spa_tx_assign_init(spa);
}
void
spa_stats_destroy(spa_t *spa)
{
+ spa_tx_assign_destroy(spa);
spa_txg_history_destroy(spa);
spa_read_history_destroy(spa);
}