dsched_fq - Improve performance, reduce idle time
authorAlex Hornung <ahornung@gmail.com>
Wed, 31 Mar 2010 01:11:29 +0000 (01:11 +0000)
committerAlex Hornung <ahornung@gmail.com>
Thu, 15 Apr 2010 20:24:48 +0000 (20:24 +0000)
* Boost performance by dynamically adapting the rate limit on throttled
  threads if the disk becomes idle. This will ensure that the disk is
  always > 90% used if there are requests queued.

sys/dsched/fq/dsched_fq.h
sys/dsched/fq/dsched_fq_core.c
sys/dsched/fq/dsched_fq_diskops.c

index 715268a..7387adb 100644 (file)
@@ -134,6 +134,7 @@ struct dsched_fq_dpriv {
        int     idle;
        struct timeval start_idle;
        int     idle_time;
+       int     die;
 
        /* list contains all fq_priv for this disk */
        TAILQ_HEAD(, dsched_fq_priv)    fq_priv_list;
index 02217a7..8cdd460 100644 (file)
@@ -339,7 +339,7 @@ fq_dispatcher(struct dsched_fq_dpriv *dpriv)
        struct dsched_fq_mpriv  *fqmp;
        struct dsched_fq_priv   *fqp, *fqp2;
        struct bio *bio, *bio2;
-       int count;
+       int count, idle;
 
        /*
         * We need to manually assign an fqp to the fqmp of this thread
@@ -360,22 +360,44 @@ fq_dispatcher(struct dsched_fq_dpriv *dpriv)
 
        FQ_DPRIV_LOCK(dpriv);
        for(;;) {
+               idle = 0;
                /* sleep ~60 ms */
-               if (ssleep(dpriv, &dpriv->lock, 0, "fq_dispatcher", hz/15) == 0) {
-                       FQ_DPRIV_UNLOCK(dpriv);
-                       kprintf("fq_dispatcher is peacefully dying\n");
-                       lwkt_exit();
+               if ((ssleep(dpriv, &dpriv->lock, 0, "fq_dispatcher", hz/15) == 0)) {
+                       if (dpriv->die == 1) {
+                               FQ_DPRIV_UNLOCK(dpriv);
+                               kprintf("fq_dispatcher is peacefully dying\n");
+                               lwkt_exit();
+                               /* NOTREACHED */
+
+                               /*
+                                * We have been awakened because the disk is idle.
+                                * So let's get ready to dispatch some extra bios.
+                                */
+                               idle = 1;
+                       }
                }
 
+               if (idle == 0)
+                       idle = dpriv->idle;
+
                TAILQ_FOREACH_MUTABLE(fqp, &dpriv->fq_priv_list, dlink, fqp2) {
                        if (fqp->qlength > 0) {
                                FQ_FQP_LOCK(fqp);
                                count = 0;
 
+                               /*
+                                * XXX: why 5 extra? should probably be dynamic,
+                                *      relying on information on latency.
+                                */
+                               if ((fqp->max_tp > 0) && idle &&
+                                   (fqp->issued >= fqp->max_tp))
+                                       fqp->max_tp += 5;
+
                                TAILQ_FOREACH_MUTABLE(bio, &fqp->queue, link, bio2) {
                                        if ((fqp->max_tp > 0) &&
                                            ((fqp->issued >= fqp->max_tp)))
                                                break;
+
                                        TAILQ_REMOVE(&fqp->queue, bio, link);
 
                                        --fqp->qlength;
index e6e7901..44edcfe 100644 (file)
@@ -145,6 +145,7 @@ fq_teardown(struct disk *dp)
 
        /* Basically kill the dispatcher thread */
        callout_stop(&fq_callout);
+       dpriv->die = 1;
        wakeup(dpriv);
        tsleep(dpriv, 0, "fq_dispatcher", hz/5); /* wait 200 ms */
        callout_stop(&fq_callout);
@@ -362,6 +363,7 @@ fq_completed(struct bio *bp)
                if ((dpriv->incomplete_tp <= 1) && (!dpriv->idle)) {
                        dpriv->idle = 1;        /* Mark disk as idle */
                        dpriv->start_idle = tv; /* Save start idle time */
+                       wakeup(dpriv);          /* Wake up fq_dispatcher */
                }
                atomic_subtract_int(&dpriv->incomplete_tp, 1);
                transactions = atomic_fetchadd_int(&fqp->transactions, 1);