]> granicus.if.org Git - zfs/commitdiff
Illumos #3537
authorMatthew Ahrens <mahrens@delphix.com>
Tue, 27 Aug 2013 00:09:29 +0000 (17:09 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 31 Oct 2013 16:16:03 +0000 (09:16 -0700)
3537 want pool io kstats

Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Reviewed by: Sa?o Kiselkov <skiselkov.ml@gmail.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Brendan Gregg <brendan.gregg@joyent.com>
Approved by: Gordon Ross <gwr@nexenta.com>

References:
  http://www.illumos.org/issues/3537
  illumos/illumos-gate@c3a6601

Ported by: Cyril Plisko <cyril.plisko@mountall.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Porting Notes:

1. The patch was restructured to take advantage of the existing
   spa statistics infrastructure.  To accomplish this the kstat
   was moved in to spa->io_stats and the init/destroy code moved
   to spa_stats.c.

2. The I/O kstat was simply named <pool> which conflicted with the
   pool directory we had already created.  Therefore it was renamed
   to <pool>/io

3. An update handler was added to allow the kstat to be zeroed.

include/sys/spa.h
include/sys/zfs_context.h
lib/libzpool/kernel.c
module/zfs/spa_stats.c
module/zfs/vdev_queue.c

index cb3ce11bca6d7ff0be82b3dd77dacade603518a4..13c9672aadb6e6b086914827f65eef7512e77070 100644 (file)
@@ -550,6 +550,7 @@ typedef struct spa_stats {
        spa_stats_history_t     read_history;
        spa_stats_history_t     txg_history;
        spa_stats_history_t     tx_assign_histogram;
+       spa_stats_history_t     io_history;
 } spa_stats_t;
 
 typedef enum txg_state {
index dfd11d9f1e5e0fb9afd79606b327977c99a92d4a..7910e08aa076d877a8d8c3bfba9264a0c4ebf66a 100644 (file)
@@ -344,10 +344,16 @@ extern void cv_broadcast(kcondvar_t *cv);
 /*
  * kstat creation, installation and deletion
  */
-extern kstat_t *kstat_create(char *, int,
-    char *, char *, uchar_t, ulong_t, uchar_t);
+extern kstat_t *kstat_create(const char *, int,
+    const char *, const char *, uchar_t, ulong_t, uchar_t);
 extern void kstat_install(kstat_t *);
 extern void kstat_delete(kstat_t *);
+extern void kstat_waitq_enter(kstat_io_t *);
+extern void kstat_waitq_exit(kstat_io_t *);
+extern void kstat_runq_enter(kstat_io_t *);
+extern void kstat_runq_exit(kstat_io_t *);
+extern void kstat_waitq_to_runq(kstat_io_t *);
+extern void kstat_runq_back_to_waitq(kstat_io_t *);
 extern void kstat_set_raw_ops(kstat_t *ksp,
     int (*headers)(char *buf, size_t size),
     int (*data)(char *buf, size_t size, void *data),
index 57a3739e23e81fb682ae9500daa93d9793522787..2e5eef69b0ad7a8f03a15f4668b72b0464d46406 100644 (file)
@@ -224,8 +224,8 @@ zk_thread_join(kt_did_t tid)
  */
 /*ARGSUSED*/
 kstat_t *
-kstat_create(char *module, int instance, char *name, char *class,
-    uchar_t type, ulong_t ndata, uchar_t ks_flag)
+kstat_create(const char *module, int instance, const char *name,
+    const char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag)
 {
        return (NULL);
 }
@@ -241,6 +241,35 @@ kstat_delete(kstat_t *ksp)
 {}
 
 /*ARGSUSED*/
+void
+kstat_waitq_enter(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_waitq_exit(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_runq_enter(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_runq_exit(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_waitq_to_runq(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_runq_back_to_waitq(kstat_io_t *kiop)
+{}
+
 void
 kstat_set_raw_ops(kstat_t *ksp,
     int (*headers)(char *buf, size_t size),
index 789e8c3e61b7763ea3c789c08706b46eb6ef3c2b..d37b0af4f93b729ceda4d119ff01101f139d9c68 100644 (file)
@@ -608,12 +608,61 @@ spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs)
        atomic_inc_64(&((kstat_named_t *)ssh->private)[idx].value.ui64);
 }
 
+/*
+ * ==========================================================================
+ * SPA IO History Routines
+ * ==========================================================================
+ */
+static int
+spa_io_history_update(kstat_t *ksp, int rw)
+{
+       if (rw == KSTAT_WRITE)
+               memset(ksp->ks_data, 0, ksp->ks_data_size);
+
+       return (0);
+}
+
+static void
+spa_io_history_init(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+       char name[KSTAT_STRLEN];
+       kstat_t *ksp;
+
+       mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
+
+       (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
+       name[KSTAT_STRLEN-1] = '\0';
+
+       ksp = kstat_create(name, 0, "io", "disk", KSTAT_TYPE_IO, 1, 0);
+       ssh->kstat = ksp;
+
+       if (ksp) {
+               ksp->ks_lock = &ssh->lock;
+               ksp->ks_private = spa;
+               ksp->ks_update = spa_io_history_update;
+               kstat_install(ksp);
+       }
+}
+
+static void
+spa_io_history_destroy(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       if (ssh->kstat)
+               kstat_delete(ssh->kstat);
+
+       mutex_destroy(&ssh->lock);
+}
+
 void
 spa_stats_init(spa_t *spa)
 {
        spa_read_history_init(spa);
        spa_txg_history_init(spa);
        spa_tx_assign_init(spa);
+       spa_io_history_init(spa);
 }
 
 void
@@ -622,6 +671,7 @@ spa_stats_destroy(spa_t *spa)
        spa_tx_assign_destroy(spa);
        spa_txg_history_destroy(spa);
        spa_read_history_destroy(spa);
+       spa_io_history_destroy(spa);
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
index b2cc6b87ffd783ea927a563f308729c59ffc0ab0..c01990bf71bd9c0186aab022049d999973dcdb9d 100644 (file)
 
 #include <sys/zfs_context.h>
 #include <sys/vdev_impl.h>
+#include <sys/spa_impl.h>
 #include <sys/zio.h>
 #include <sys/avl.h>
+#include <sys/kstat.h>
 
 /*
  * These tunables are for performance analysis.
@@ -164,15 +166,72 @@ vdev_queue_fini(vdev_t *vd)
 static void
 vdev_queue_io_add(vdev_queue_t *vq, zio_t *zio)
 {
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
        avl_add(&vq->vq_deadline_tree, zio);
        avl_add(zio->io_vdev_tree, zio);
+
+       if (ssh->kstat != NULL) {
+               mutex_enter(&ssh->lock);
+               kstat_waitq_enter(ssh->kstat->ks_data);
+               mutex_exit(&ssh->lock);
+       }
 }
 
 static void
 vdev_queue_io_remove(vdev_queue_t *vq, zio_t *zio)
 {
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
        avl_remove(&vq->vq_deadline_tree, zio);
        avl_remove(zio->io_vdev_tree, zio);
+
+       if (ssh->kstat != NULL) {
+               mutex_enter(&ssh->lock);
+               kstat_waitq_exit(ssh->kstat->ks_data);
+               mutex_exit(&ssh->lock);
+       }
+}
+
+static void
+vdev_queue_pending_add(vdev_queue_t *vq, zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       avl_add(&vq->vq_pending_tree, zio);
+
+       if (ssh->kstat != NULL) {
+               mutex_enter(&ssh->lock);
+               kstat_runq_enter(ssh->kstat->ks_data);
+               mutex_exit(&ssh->lock);
+       }
+}
+
+static void
+vdev_queue_pending_remove(vdev_queue_t *vq, zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       avl_remove(&vq->vq_pending_tree, zio);
+
+       if (ssh->kstat != NULL) {
+               kstat_io_t *ksio = ssh->kstat->ks_data;
+
+               mutex_enter(&ssh->lock);
+               kstat_runq_exit(ksio);
+               if (zio->io_type == ZIO_TYPE_READ) {
+                       ksio->reads++;
+                       ksio->nread += zio->io_size;
+               } else if (zio->io_type == ZIO_TYPE_WRITE) {
+                       ksio->writes++;
+                       ksio->nwritten += zio->io_size;
+               }
+               mutex_exit(&ssh->lock);
+       }
 }
 
 static void
@@ -351,7 +410,7 @@ again:
                        zio_execute(dio);
                } while (dio != lio);
 
-               avl_add(&vq->vq_pending_tree, aio);
+               vdev_queue_pending_add(vq, aio);
                list_remove(&vq->vq_io_list, vi);
 
                return (aio);
@@ -374,7 +433,7 @@ again:
                goto again;
        }
 
-       avl_add(&vq->vq_pending_tree, fio);
+       vdev_queue_pending_add(vq, fio);
 
        return (fio);
 }
@@ -431,7 +490,7 @@ vdev_queue_io_done(zio_t *zio)
 
        mutex_enter(&vq->vq_lock);
 
-       avl_remove(&vq->vq_pending_tree, zio);
+       vdev_queue_pending_remove(vq, zio);
 
        zio->io_delta = gethrtime() - zio->io_timestamp;
        vq->vq_io_complete_ts = gethrtime();