Index: /trunk/src/VBox/Devices/Storage/DrvVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 64834)
+++ /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 64835)
@@ -414,9 +414,29 @@
     /** @name Statistics.
      * @{ */
-    /** how many attempts were made to query a direct buffer pointer from the
+    /** How many attempts were made to query a direct buffer pointer from the
      * device/driver above. */
     STAMCOUNTER              StatQueryBufAttempts;
     /** How many attempts to query a direct buffer pointer succeeded. */
     STAMCOUNTER              StatQueryBufSuccess;
+    /** Release statistics: number of bytes written. */
+    STAMCOUNTER              StatBytesWritten;
+    /** Release statistics: number of bytes read. */
+    STAMCOUNTER              StatBytesRead;
+    /** Release statistics: Number of requests submitted. */
+    STAMCOUNTER              StatReqsSubmitted;
+    /** Release statistics: Number of requests failed. */
+    STAMCOUNTER              StatReqsFailed;
+    /** Release statistics: Number of requests succeeded. */
+    STAMCOUNTER              StatReqsSucceeded;
+    /** Release statistics: Number of flush requests. */
+    STAMCOUNTER              StatReqsFlush;
+    /** Release statistics: Number of write requests. */
+    STAMCOUNTER              StatReqsWrite;
+    /** Release statistics: Number of read requests. */
+    STAMCOUNTER              StatReqsRead;
+    /** Release statistics: Number of discard requests. */
+    STAMCOUNTER              StatReqsDiscard;
+    /** Release statistics: Number of I/O requests processed per second. */
+    STAMCOUNTER              StatReqsPerSec;
     /** @} */
 } VBOXDISK;
@@ -1891,4 +1911,7 @@
         return rc;
 
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsRead);
+
     if (!pThis->fBootAccelActive)
         rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
@@ -1926,6 +1949,12 @@
 
     if (RT_SUCCESS(rc))
+    {
+        STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
         Log2(("%s: off=%#llx pvBuf=%p cbRead=%d\n%.*Rhxd\n", __FUNCTION__,
               off, pvBuf, cbRead, cbRead, pvBuf));
+    }
+    else
+        STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
+
     LogFlowFunc(("returns %Rrc\n", rc));
     return rc;
@@ -2029,4 +2058,7 @@
     }
 
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsWrite);
+
     rc = VDWrite(pThis->pDisk, off, pvBuf, cbWrite);
 #ifdef VBOX_PERIODIC_FLUSH
@@ -2041,4 +2073,9 @@
     }
 #endif /* VBOX_PERIODIC_FLUSH */
+
+    if (RT_SUCCESS(rc))
+        STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
+    else
+        STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
 
     LogFlowFunc(("returns %Rrc\n", rc));
@@ -2066,5 +2103,13 @@
 #endif /* VBOX_IGNORE_FLUSH */
 
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsFlush);
+
     int rc = VDFlush(pThis->pDisk);
+    if (RT_SUCCESS(rc))
+        STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
+    else
+        STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
+
     LogFlowFunc(("returns %Rrc\n", rc));
     return rc;
@@ -2407,5 +2452,13 @@
     PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
 
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsDiscard);
+
     int rc = VDDiscardRanges(pThis->pDisk, paRanges, cRanges);
+    if (RT_SUCCESS(rc))
+        STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
+    else
+        STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
+
     LogFlowFunc(("returns %Rrc\n", rc));
     return rc;
@@ -2832,4 +2885,22 @@
             }
         }
+
+        STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
+    }
+    else
+    {
+        STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
+
+        switch (pIoReq->enmType)
+        {
+            case PDMMEDIAEXIOREQTYPE_READ:
+                STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, pIoReq->ReadWrite.cbReq);
+                break;
+            case PDMMEDIAEXIOREQTYPE_WRITE:
+                STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, pIoReq->ReadWrite.cbReq);
+                break;
+            default:
+                break;
+        }
     }
 
@@ -3579,4 +3650,7 @@
         return VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE;
 
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsRead);
+
     pIoReq->enmType             = PDMMEDIAEXIOREQTYPE_READ;
     pIoReq->tsSubmit            = RTTimeMilliTS();
@@ -3618,4 +3692,7 @@
         return VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE;
 
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsWrite);
+
     pIoReq->enmType             = PDMMEDIAEXIOREQTYPE_WRITE;
     pIoReq->tsSubmit            = RTTimeMilliTS();
@@ -3657,4 +3734,7 @@
         return VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE;
 
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsFlush);
+
     pIoReq->enmType  = PDMMEDIAEXIOREQTYPE_FLUSH;
     pIoReq->tsSubmit = RTTimeMilliTS();
@@ -3694,4 +3774,7 @@
     if (RT_UNLIKELY(enmState != VDIOREQSTATE_ALLOCATED))
         return VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE;
+
+    STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
+    STAM_REL_COUNTER_INC(&pThis->StatReqsDiscard);
 
     /* Copy the ranges over now, this can be optimized in the future. */
@@ -4112,4 +4195,89 @@
 }
 
+/**
+ * Registers statistics associated with the given media driver.
+ *
+ * @returns VBox status code.
+ * @param   pThis      The media driver instance.
+ */
+static int drvvdStatsRegister(PVBOXDISK pThis)
+{
+    PPDMDRVINS pDrvIns = pThis->pDrvIns;
+    uint32_t iInstance, iLUN;
+    const char *pcszController;
+
+    int rc = pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, &pcszController,
+                                                          &iInstance, &iLUN);
+    if (RT_SUCCESS(rc))
+    {
+        char *pszCtrlUpper = RTStrDup(pcszController);
+        if (pszCtrlUpper)
+        {
+            RTStrToUpper(pszCtrlUpper);
+
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatQueryBufAttempts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                   STAMUNIT_COUNT, "Number of attempts to query a direct buffer.",
+                                   "/Devices/%s%u/Port%u/QueryBufAttempts", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatQueryBufSuccess, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
+                                   STAMUNIT_COUNT, "Number of succeeded attempts to query a direct buffer.",
+                                   "/Devices/%s%u/Port%u/QueryBufSuccess", pszCtrlUpper, iInstance, iLUN);
+
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
+                                   "Amount of data read.", "/Devices/%s%u/Port%u/ReadBytes", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
+                                   "Amount of data written.", "/Devices/%s%u/Port%u/WrittenBytes", pszCtrlUpper, iInstance, iLUN);
+
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
+                                   "Number of I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsSubmitted", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
+                                   "Number of I/O requests failed.", "/Devices/%s%u/Port%u/ReqsFailed", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsSucceeded, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
+                                   "Number of I/O requests succeeded.", "/Devices/%s%u/Port%u/ReqsSucceeded", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsFlush, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
+                                   "Number of flush I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsFlush", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsWrite, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
+                                   "Number of write I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsWrite", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
+                                   "Number of read I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsRead", pszCtrlUpper, iInstance, iLUN);
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsDiscard, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
+                                   "Number of discard I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsDiscard", pszCtrlUpper, iInstance, iLUN);
+
+            PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsPerSec, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
+                                   "Number of processed I/O requests per second.", "/Devices/%s%u/Port%u/ReqsPerSec",
+                                   pszCtrlUpper, iInstance, iLUN);
+
+            RTStrFree(pszCtrlUpper);
+        }
+        else
+            rc = VERR_NO_STR_MEMORY;
+    }
+
+    return rc;
+}
+
+/**
+ * Deregisters statistics associated with the given media driver.
+ *
+ * @returns nothing.
+ * @param   pThis      The media driver instance.
+ */
+static void drvvdStatsDeregister(PVBOXDISK pThis)
+{
+    PPDMDRVINS pDrvIns = pThis->pDrvIns;
+
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatQueryBufAttempts);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatQueryBufSuccess);
+
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesRead);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesWritten);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsSubmitted);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsFailed);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsSucceeded);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsFlush);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsWrite);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsRead);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsDiscard);
+    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsPerSec);
+}
 
 /*********************************************************************************************************************************
@@ -4415,6 +4583,5 @@
             RTSemFastMutexDestroy(pThis->aIoReqAllocBins[i].hMtxLstIoReqAlloc);
 
-    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatQueryBufAttempts);
-    PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatQueryBufSuccess);
+    drvvdStatsDeregister(pThis);
 }
 
@@ -5408,8 +5575,6 @@
     } /* !fEmptyDrive */
 
-    PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->StatQueryBufAttempts, "QueryBufAttempts",
-                              STAMUNIT_COUNT, "Number of attempts to query a direct buffer.");
-    PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->StatQueryBufSuccess, "QueryBufSuccess",
-                              STAMUNIT_COUNT, "Number of succeeded attempts to query a direct buffer.");
+    if (RT_SUCCESS(rc))
+        drvvdStatsRegister(pThis);
 
     if (RT_FAILURE(rc))
