Author: sephe
Date: Thu Aug 25 05:50:19 2016
New Revision: 304791
URL: https://svnweb.freebsd.org/changeset/base/304791

Log:
  hyperv/storvsc: Increase queue depth and rework channel selection.
  
  - Increasing queue depth gives ~100% performance improvement for
    randwrite fio test in Azure.
  - New channel selection, which takes LUN id and the current cpuid
    into consideration, gives additional ~20% performance improvement
    for ranwrite fio test in Azure.
  
  Submitted by:   Hongzhang Jiang <honzhan microsoft com>
  Modified by:    sephe
  MFC after:    1 week
  Sponsored by: Microsoft
  Differential Revision:        https://reviews.freebsd.org/D7622

Modified:
  head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
  head/sys/dev/hyperv/storvsc/hv_vstorage.h

Modified: head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c        Thu Aug 25 
05:35:51 2016        (r304790)
+++ head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c        Thu Aug 25 
05:50:19 2016        (r304791)
@@ -75,11 +75,9 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/hyperv/include/hyperv.h>
 #include <dev/hyperv/include/vmbus.h>
-
 #include "hv_vstorage.h"
 #include "vmbus_if.h"
 
-#define STORVSC_RINGBUFFER_SIZE                (20*PAGE_SIZE)
 #define STORVSC_MAX_LUNS_PER_TARGET    (64)
 #define STORVSC_MAX_IO_REQUESTS                (STORVSC_MAX_LUNS_PER_TARGET * 
2)
 #define BLKVSC_MAX_IDE_DISKS_PER_TARGET        (1)
@@ -121,8 +119,6 @@ struct hv_sgl_page_pool{
        boolean_t                is_init;
 } g_hv_sgl_page_pool;
 
-#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * 
STORVSC_DATA_SEGCNT_MAX
-
 enum storvsc_request_type {
        WRITE_TYPE,
        READ_TYPE,
@@ -130,17 +126,35 @@ enum storvsc_request_type {
 };
 
 SYSCTL_NODE(_hw, OID_AUTO, storvsc, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
-    "Hyper-V storage interface");
+       "Hyper-V storage interface");
+
+static u_int hv_storvsc_use_win8ext_flags = 1;
+SYSCTL_UINT(_hw_storvsc, OID_AUTO, use_win8ext_flags, CTLFLAG_RW,
+       &hv_storvsc_use_win8ext_flags, 0,
+       "Use win8 extension flags or not");
 
 static u_int hv_storvsc_use_pim_unmapped = 1;
-SYSCTL_INT(_hw_storvsc, OID_AUTO, use_pim_unmapped, CTLFLAG_RDTUN,
-    &hv_storvsc_use_pim_unmapped, 0,
-    "Optimize storvsc by using unmapped I/O");
+SYSCTL_UINT(_hw_storvsc, OID_AUTO, use_pim_unmapped, CTLFLAG_RDTUN,
+       &hv_storvsc_use_pim_unmapped, 0,
+       "Optimize storvsc by using unmapped I/O");
+
+static u_int hv_storvsc_ringbuffer_size = (64 * PAGE_SIZE);
+SYSCTL_UINT(_hw_storvsc, OID_AUTO, ringbuffer_size, CTLFLAG_RDTUN,
+       &hv_storvsc_ringbuffer_size, 0, "Hyper-V storage ringbuffer size");
+
+static u_int hv_storvsc_max_io = 512;
+SYSCTL_UINT(_hw_storvsc, OID_AUTO, max_io, CTLFLAG_RDTUN,
+       &hv_storvsc_max_io, 0, "Hyper-V storage max io limit");
+
+#define STORVSC_MAX_IO                                         \
+       vmbus_chan_prplist_nelem(hv_storvsc_ringbuffer_size,    \
+          STORVSC_DATA_SEGCNT_MAX, VSTOR_PKT_SIZE)
 
 struct hv_storvsc_sysctl {
        u_long          data_bio_cnt;
        u_long          data_vaddr_cnt;
        u_long          data_sg_cnt;
+       u_long          chan_send_cnt[MAXCPU];
 };
 
 struct storvsc_gpa_range {
@@ -184,10 +198,18 @@ struct storvsc_softc {
        device_t                        hs_dev;
        bus_dma_tag_t                   storvsc_req_dtag;
        struct hv_storvsc_sysctl        sysctl_data;
-
-       struct vmbus_channel            *hs_cpu2chan[MAXCPU];
+       uint32_t                        hs_nchan;
+       struct vmbus_channel            *hs_sel_chan[MAXCPU];
 };
 
+/*
+ * The size of the vmscsi_request has changed in win8. The
+ * additional size is for the newly added elements in the
+ * structure. These elements are valid only when we are talking
+ * to a win8 host.
+ * Track the correct size we need to apply.
+ */
+static int vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
 
 /**
  * HyperV storvsc timeout testing cases:
@@ -211,7 +233,7 @@ struct storvsc_driver_props {
        char            *drv_name;
        char            *drv_desc;
        uint8_t         drv_max_luns_per_target;
-       uint8_t         drv_max_ios_per_target;
+       uint32_t        drv_max_ios_per_target;
        uint32_t        drv_ringbuffer_size;
 };
 
@@ -240,10 +262,10 @@ static const struct hyperv_guid gBlkVscD
 static struct storvsc_driver_props g_drv_props_table[] = {
        {"blkvsc", "Hyper-V IDE Storage Interface",
         BLKVSC_MAX_IDE_DISKS_PER_TARGET, BLKVSC_MAX_IO_REQUESTS,
-        STORVSC_RINGBUFFER_SIZE},
+        20*PAGE_SIZE},
        {"storvsc", "Hyper-V SCSI Storage Interface",
         STORVSC_MAX_LUNS_PER_TARGET, STORVSC_MAX_IO_REQUESTS,
-        STORVSC_RINGBUFFER_SIZE}
+        20*PAGE_SIZE}
 };
 
 /*
@@ -253,14 +275,6 @@ static struct storvsc_driver_props g_drv
 static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
 
 /*
- * The size of the vmscsi_request has changed in win8. The
- * additional size is for the newly added elements in the
- * structure. These elements are valid only when we are talking
- * to a win8 host.
- * Track the correct size we need to apply.
- */
-static int vmscsi_size_delta;
-/*
  * The storage protocol version is determined during the
  * initial exchange with the host.  It will indicate which
  * storage functionality is available in the host.
@@ -413,6 +427,9 @@ storvsc_send_multichannel_request(struct
                return;
        }
 
+       /* Update channel count */
+       sc->hs_nchan = request_channels_cnt + 1;
+
        /* Wait for sub-channels setup to complete. */
        subchan = vmbus_subchan_get(sc->hs_chan, request_channels_cnt);
 
@@ -585,7 +602,6 @@ hv_storvsc_channel_init(struct storvsc_s
         */
        if (support_multichannel)
                storvsc_send_multichannel_request(sc, max_chans);
-
 cleanup:
        sema_destroy(&request->synch_sema);
        return (ret);
@@ -624,7 +640,6 @@ hv_storvsc_connect_vsp(struct storvsc_so
        }
 
        ret = hv_storvsc_channel_init(sc);
-
        return (ret);
 }
 
@@ -686,7 +701,7 @@ hv_storvsc_io_request(struct storvsc_sof
 {
        struct vstor_packet *vstor_packet = &request->vstor_packet;
        struct vmbus_channel* outgoing_channel = NULL;
-       int ret = 0;
+       int ret = 0, ch_sel;
 
        vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
 
@@ -699,7 +714,8 @@ hv_storvsc_io_request(struct storvsc_sof
 
        vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB;
 
-       outgoing_channel = sc->hs_cpu2chan[curcpu];
+       ch_sel = (vstor_packet->u.vm_srb.lun + curcpu) % sc->hs_nchan;
+       outgoing_channel = sc->hs_sel_chan[ch_sel];
 
        mtx_unlock(&request->softc->hs_lock);
        if (request->prp_list.gpa_range.gpa_len) {
@@ -711,6 +727,10 @@ hv_storvsc_io_request(struct storvsc_sof
                    VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
                    vstor_packet, VSTOR_PKT_SIZE, (uint64_t)(uintptr_t)request);
        }
+       /* statistic for successful request sending on each channel */
+       if (!ret) {
+               sc->sysctl_data.chan_send_cnt[ch_sel]++;
+       }
        mtx_lock(&request->softc->hs_lock);
 
        if (ret != 0) {
@@ -906,17 +926,20 @@ storvsc_probe(device_t dev)
 }
 
 static void
-storvsc_create_cpu2chan(struct storvsc_softc *sc)
+storvsc_create_chan_sel(struct storvsc_softc *sc)
 {
-       int cpu;
+       struct vmbus_channel **subch;
+       int i, nsubch;
 
-       CPU_FOREACH(cpu) {
-               sc->hs_cpu2chan[cpu] = vmbus_chan_cpu2chan(sc->hs_chan, cpu);
-               if (bootverbose) {
-                       device_printf(sc->hs_dev, "cpu%d -> chan%u\n",
-                           cpu, vmbus_chan_id(sc->hs_cpu2chan[cpu]));
-               }
-       }
+       sc->hs_sel_chan[0] = sc->hs_chan;
+       nsubch = sc->hs_nchan - 1;
+       if (nsubch == 0)
+               return;
+
+       subch = vmbus_subchan_get(sc->hs_chan, nsubch);
+       for (i = 0; i < nsubch; i++)
+               sc->hs_sel_chan[i + 1] = subch[i];
+       vmbus_subchan_rel(subch, nsubch);
 }
 
 static int
@@ -976,7 +999,10 @@ storvsc_sysctl(device_t dev)
 {
        struct sysctl_oid_list *child;
        struct sysctl_ctx_list *ctx;
+       struct sysctl_oid *ch_tree, *chid_tree;
        struct storvsc_softc *sc;
+       char name[16];
+       int i;
 
        sc = device_get_softc(dev);
        ctx = device_get_sysctl_ctx(dev);
@@ -988,6 +1014,28 @@ storvsc_sysctl(device_t dev)
                &sc->sysctl_data.data_vaddr_cnt, "# of vaddr data block");
        SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "data_sg_cnt", CTLFLAG_RW,
                &sc->sysctl_data.data_sg_cnt, "# of sg data block");
+
+       /* dev.storvsc.UNIT.channel */
+       ch_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "channel",
+               CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+       if (ch_tree == NULL)
+               return;
+
+       for (i = 0; i < sc->hs_nchan; i++) {
+               uint32_t ch_id;
+
+               ch_id = vmbus_chan_id(sc->hs_sel_chan[i]);
+               snprintf(name, sizeof(name), "%d", ch_id);
+               /* dev.storvsc.UNIT.channel.CHID */
+               chid_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(ch_tree),
+                       OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+               if (chid_tree == NULL)
+                       return;
+               /* dev.storvsc.UNIT.channel.CHID.send_req */
+               SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO,
+                       "send_req", CTLFLAG_RD, 
&sc->sysctl_data.chan_send_cnt[i],
+                       "# of request sending from this channel");
+       }
 }
 
 /**
@@ -1018,6 +1066,7 @@ storvsc_attach(device_t dev)
        root_mount_token = root_mount_hold("storvsc");
 
        sc = device_get_softc(dev);
+       sc->hs_nchan = 1;
        sc->hs_chan = vmbus_get_channel(dev);
 
        stor_type = storvsc_get_storage_type(dev);
@@ -1029,7 +1078,14 @@ storvsc_attach(device_t dev)
 
        /* fill in driver specific properties */
        sc->hs_drv_props = &g_drv_props_table[stor_type];
-
+       sc->hs_drv_props->drv_ringbuffer_size = hv_storvsc_ringbuffer_size;
+       sc->hs_drv_props->drv_max_ios_per_target =
+               MIN(STORVSC_MAX_IO, hv_storvsc_max_io);
+       if (bootverbose) {
+               printf("storvsc ringbuffer size: %d, max_io: %d\n",
+                       sc->hs_drv_props->drv_ringbuffer_size,
+                       sc->hs_drv_props->drv_max_ios_per_target);
+       }
        /* fill in device specific properties */
        sc->hs_unit     = device_get_unit(dev);
        sc->hs_dev      = dev;
@@ -1051,7 +1107,7 @@ storvsc_attach(device_t dev)
                 * STORVSC_DATA_SEGCNT_MAX segments, each
                 * segment has one page buffer
                 */
-               for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++) {
+               for (i = 0; i < sc->hs_drv_props->drv_max_ios_per_target; i++) {
                        sgl_node = malloc(sizeof(struct hv_sgl_node),
                            M_DEVBUF, M_WAITOK|M_ZERO);
 
@@ -1082,7 +1138,7 @@ storvsc_attach(device_t dev)
        }
 
        /* Construct cpu to channel mapping */
-       storvsc_create_cpu2chan(sc);
+       storvsc_create_chan_sel(sc);
 
        /*
         * Create the device queue.
@@ -1839,19 +1895,37 @@ create_storvsc_request(union ccb *ccb, s
                        csio->cdb_len);
        }
 
+       if (hv_storvsc_use_win8ext_flags) {
+               reqp->vstor_packet.u.vm_srb.win8_extension.time_out_value = 60;
+               reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |=
+                       SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+       }
        switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
        case CAM_DIR_OUT:
-               reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE;       
+               reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE;
+               if (hv_storvsc_use_win8ext_flags) {
+                       reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |=
+                               SRB_FLAGS_DATA_OUT;
+               }
                break;
        case CAM_DIR_IN:
                reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE;
+               if (hv_storvsc_use_win8ext_flags) {
+                       reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |=
+                               SRB_FLAGS_DATA_IN;
+               }
                break;
        case CAM_DIR_NONE:
                reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
+               if (hv_storvsc_use_win8ext_flags) {
+                       reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |=
+                               SRB_FLAGS_NO_DATA_TRANSFER;
+               }
                break;
        default:
-               reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
-               break;
+               printf("Error: unexpected data direction: 0x%x\n",
+                       ccb->ccb_h.flags & CAM_DIR_MASK);
+               return (EINVAL);
        }
 
        reqp->sense_data     = &csio->sense_data;

Modified: head/sys/dev/hyperv/storvsc/hv_vstorage.h
==============================================================================
--- head/sys/dev/hyperv/storvsc/hv_vstorage.h   Thu Aug 25 05:35:51 2016        
(r304790)
+++ head/sys/dev/hyperv/storvsc/hv_vstorage.h   Thu Aug 25 05:50:19 2016        
(r304791)
@@ -253,6 +253,22 @@ struct vstor_packet {
 #define SRB_STATUS_AUTOSENSE_VALID      0x80
 #define SRB_STATUS_INVALID_LUN          0X20
 
+/*
+ * SRB Flag Bits
+ */
+
+#define SRB_FLAGS_QUEUE_ACTION_ENABLE           0x00000002
+#define SRB_FLAGS_DISABLE_DISCONNECT            0x00000004
+#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER        0x00000008
+#define SRB_FLAGS_BYPASS_FROZEN_QUEUE           0x00000010
+#define SRB_FLAGS_DISABLE_AUTOSENSE             0x00000020
+#define SRB_FLAGS_DATA_IN                       0x00000040
+#define SRB_FLAGS_DATA_OUT                      0x00000080
+#define SRB_FLAGS_NO_DATA_TRANSFER              0x00000000
+#define SRB_FLAGS_UNSPECIFIED_DIRECTION (SRB_FLAGS_DATA_IN | 
SRB_FLAGS_DATA_OUT)
+#define SRB_FLAGS_NO_QUEUE_FREEZE               0x00000100
+#define SRB_FLAGS_ADAPTER_CACHE_ENABLE          0x00000200
+#define SRB_FLAGS_FREE_SENSE_BUFFER             0x00000400
 /**
  *  Packet flags
  */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to